home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / ps.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-03-22  |  85.3 KB  |  3,071 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  * PostScript file plugin
  4.  * PostScript writing and GhostScript interfacing code
  5.  * Copyright (C) 1997-98 Peter Kirchgessner
  6.  * (email: peter@kirchgessner.net, WWW: http://www.kirchgessner.net)
  7.  *
  8.  * Added controls for TextAlphaBits and GraphicsAlphaBits
  9.  *   George White <aa056@chebucto.ns.ca>
  10.  *
  11.  * Added Ascii85 encoding
  12.  *   Austin Donnelly <austin@gimp.org>
  13.  *
  14.  * This program is free software; you can redistribute it and/or modify
  15.  * it under the terms of the GNU General Public License as published by
  16.  * the Free Software Foundation; either version 2 of the License, or
  17.  * (at your option) any later version.
  18.  *
  19.  * This program is distributed in the hope that it will be useful,
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  * GNU General Public License for more details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with this program; if not, write to the Free Software
  26.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27.  *
  28.  */
  29.  
  30. /* Event history:
  31.  * V 0.90, PK, 28-Mar-97: Creation.
  32.  * V 0.91, PK, 03-Apr-97: Clip everything outside BoundingBox.
  33.  *             24-Apr-97: Multi page read support.
  34.  * V 1.00, PK, 30-Apr-97: PDF support.
  35.  * V 1.01, PK, 05-Oct-97: Parse rc-file.
  36.  * V 1.02, GW, 09-Oct-97: Antialiasing support.
  37.  *         PK, 11-Oct-97: No progress bars when running non-interactive.
  38.  *                        New procedure file_ps_load_setargs to set
  39.  *                        load-arguments non-interactively.
  40.  *                        If GS_OPTIONS are not set, use at least "-dSAFER"
  41.  * V 1.03, nn, 20-Dec-97: Initialize some variables
  42.  * V 1.04, PK, 20-Dec-97: Add Encapsulated PostScript output and preview
  43.  * V 1.05, PK, 21-Sep-98: Write b/w-images (indexed) using image-operator
  44.  * V 1.06, PK, 22-Dec-98: Fix problem with writing color PS files.
  45.  *                        Ghostview may hang when displaying the files.
  46.  * V 1.07, PK, 14-Sep-99: Add resolution to image
  47.  * V 1.08, PK, 16-Jan-2000: Add PostScript-Level 2 by Austin Donnelly
  48.  * V 1.09, PK, 15-Feb-2000: Force showpage on EPS-files
  49.  *                          Add "RunLength" compression
  50.  *                          Fix problem with "Level 2" toggle
  51.  * V 1.10, PK, 15-Mar-2000: For load EPSF, allow negative Bounding Box Values
  52.  *                          Save PS: dont start lines of image data with %%
  53.  *                          to prevent problems with stupid PostScript
  54.  *                          analyzer programs (Stanislav Brabec)
  55.  *                          Add BeginData/EndData comments
  56.  *                          Save PS: Set default rotation to 0
  57.  * V 1.11, PK, 20-Aug-2000: Fix problem with BoundingBox recognition
  58.  *                          for Mac files.
  59.  *                          Fix problem with loop when reading not all
  60.  *                          images of a multi page file.
  61.  *         PK, 31-Aug-2000: Load PS: Add checks for space in filename.
  62.  * V 1.12  PK, 19-Jun-2001: Fix problem with command line switch --
  63.  *                          (reported by Ferenc Wagner)
  64.  * V 1.13  PK, 07-Apr-2002: Fix problem with DOS binary EPS files
  65.  * V 1.14  PK, 14-May-2002: Workaround EPS files of Adb. Ill. 8.0
  66.  * V 1.15  PK, 04-Oct-2002: Be more accurate with using BoundingBox
  67.  */
  68. #define VERSIO 1.15
  69. static char dversio[] = "v1.15  04-Oct-2002";
  70. static char ident[] = "@(#) GIMP PostScript/PDF file-plugin v1.15  04-Oct-2002";
  71.  
  72. #include "config.h"
  73.  
  74. #include <stdio.h>
  75. #include <stdlib.h>
  76. #include <string.h>
  77. #include <time.h>
  78.  
  79. #include <libgimp/gimp.h>
  80. #include <libgimp/gimpui.h>
  81.  
  82. #include "libgimp/stdplugins-intl.h"
  83.  
  84.  
  85. #ifdef G_OS_WIN32
  86. #include <process.h>        /* For _getpid() */
  87.  
  88. #define USE_REAL_OUTPUTFILE
  89. #endif
  90.  
  91. #define STR_LENGTH 64
  92.  
  93. #ifndef G_OS_WIN32
  94. #define DEFAULT_GS_PROG "gs"
  95. #else
  96. /* We want the console ghostscript application. It should be in the PATH */
  97. #define DEFAULT_GS_PROG "gswin32c"
  98. #endif
  99.  
  100.  
  101. /* Load info */
  102. typedef struct
  103. {
  104.   guint resolution;        /* resolution (dpi) at which to run ghostscript */
  105.   guint width, height;     /* desired size (ghostscript may ignore this) */
  106.   gint  use_bbox;          /* 0: use width/height, 1: try to use BoundingBox */
  107.   gchar pages[STR_LENGTH]; /* Pages to load (eg.: 1,3,5-7) */
  108.   gint  pnm_type;          /* 4: pbm, 5: pgm, 6: ppm, 7: automatic */
  109.   gint  textalpha;         /* antialiasing: 1,2, or 4 TextAlphaBits */
  110.   gint  graphicsalpha;     /* antialiasing: 1,2, or 4 GraphicsAlphaBits */
  111. } PSLoadVals;
  112.  
  113. typedef struct
  114. {
  115.   gint  run;  /*  run  */
  116. } PSLoadInterface;
  117.  
  118. static PSLoadVals plvals =
  119. {
  120.   100,                  /* 100 dpi */
  121.   826, 1170,            /* default width/height (A4) */
  122.   1,                    /* try to use BoundingBox */
  123.   "1-99",               /* pages to load */
  124.   6,                    /* use ppm (colour) */
  125.   1,                    /* dont use text antialiasing */
  126.   1                     /* dont use graphics antialiasing */
  127. };
  128.  
  129. static PSLoadInterface plint =
  130. {
  131.   FALSE     /* run */
  132. };
  133.  
  134.  
  135. /* Save info  */
  136. typedef struct
  137. {
  138.   gdouble width, height;      /* Size of image */
  139.   gdouble x_offset, y_offset; /* Offset to image on page */
  140.   gint    unit_mm;            /* Unit of measure (0: inch, 1: mm) */
  141.   gint    keep_ratio;         /* Keep aspect ratio */
  142.   gint    rotate;             /* Rotation (0, 90, 180, 270) */
  143.   gint    level;              /* PostScript Level */
  144.   gint    eps;                /* Encapsulated PostScript flag */
  145.   gint    preview;            /* Preview Flag */
  146.   gint    preview_size;       /* Preview size */
  147. } PSSaveVals;
  148.  
  149. typedef struct
  150. {
  151.   gint  run;  /*  run  */
  152. } PSSaveInterface;
  153.  
  154. static PSSaveVals psvals =
  155. {
  156.   287.0, 200.0,   /* Image size (A4) */
  157.   5.0, 5.0,       /* Offset */
  158.   1,              /* Unit is mm */
  159.   1,              /* Keep edge ratio */
  160.   0,              /* Rotate */
  161.   2,              /* PostScript Level */
  162.   0,              /* Encapsulated PostScript flag */
  163.   0,              /* Preview flag */
  164.   256             /* Preview size */
  165. };
  166.  
  167. static PSSaveInterface psint =
  168. {
  169.   FALSE     /* run */
  170. };
  171.  
  172.  
  173. /* Declare some local functions.
  174.  */
  175. static void   query      (void);
  176. static void   run        (gchar   *name,
  177.                           gint     nparams,
  178.                           GimpParam  *param,
  179.                           gint    *nreturn_vals,
  180.                           GimpParam **return_vals);
  181.  
  182. static gint32 load_image (gchar   *filename);
  183. static gint   save_image (gchar   *filename,
  184.                           gint32   image_ID,
  185.                           gint32   drawable_ID);
  186.  
  187. static gint save_gray  (FILE   *ofp,
  188.                         gint32  image_ID,
  189.                         gint32  drawable_ID);
  190. static gint save_bw    (FILE   *ofp,
  191.                         gint32  image_ID,
  192.                         gint32  drawable_ID);
  193. static gint save_index (FILE   *ofp,
  194.                         gint32  image_ID,
  195.                         gint32  drawable_ID);
  196. static gint save_rgb   (FILE   *ofp,
  197.                         gint32  image_ID,
  198.                         gint32  drawable_ID);
  199.  
  200. static gint32 create_new_image (gchar      *filename,
  201.                 guint       pagenum,
  202.                 guint       width,
  203.                 guint       height,
  204.                 GimpImageBaseType  type,
  205.                 gint32     *layer_ID,
  206.                 GimpDrawable **drawable,
  207.                 GimpPixelRgn  *pixel_rgn);
  208.  
  209. static void   check_load_vals  (void);
  210. static void   check_save_vals  (void);
  211.  
  212. static gint   page_in_list  (gchar *list,
  213.                  guint  pagenum);
  214.  
  215. static gint   get_bbox      (gchar *filename,
  216.                  gint  *x0,
  217.                  gint  *y0,
  218.                  gint  *x1,
  219.                  gint  *y1);
  220.  
  221. static FILE  *ps_open       (gchar            *filename,
  222.                  const PSLoadVals *loadopt,
  223.                  gint             *llx,
  224.                  gint             *lly,
  225.                  gint             *urx,
  226.                  gint             *ury,
  227.                  gint             *is_epsf);
  228.  
  229. static void   ps_close      (FILE *ifp);
  230.  
  231. static gint32 skip_ps       (FILE *ifp);
  232.  
  233. static gint32 load_ps       (gchar *filename,
  234.                  guint  pagenum,
  235.                  FILE  *ifp,
  236.                  gint   llx,
  237.                  gint   lly,
  238.                  gint   urx,
  239.                  gint   ury);
  240.  
  241. static void save_ps_header  (FILE   *ofp,
  242.                  gchar  *filename);
  243. static void save_ps_setup   (FILE   *ofp,
  244.                  gint32  drawable_ID,
  245.                  gint    width,
  246.                  gint    height,
  247.                  gint    bpp);
  248. static void save_ps_trailer (FILE   *ofp);
  249. static void save_ps_preview (FILE   *ofp,
  250.                              gint32  drawable_ID);
  251. static void dither_grey     (guchar *grey,
  252.                  guchar *bw,
  253.                  gint    npix,
  254.                  gint    linecount);
  255.  
  256.  
  257. /* Misc utility from glib2 */
  258. static gchar *g_shell_quote (const gchar *unquoted_string);
  259.  
  260.  
  261. /* Dialog-handling */
  262.  
  263. static gint   load_dialog               (void);
  264. static void   load_ok_callback          (GtkWidget *widget,
  265.                      gpointer   data);
  266. static void   load_pages_entry_callback (GtkWidget *widget,
  267.                      gpointer   data);
  268.  
  269. typedef struct
  270. {
  271.   GtkObject *adjustment[4];
  272.   gint       level;
  273. } SaveDialogVals;
  274.  
  275. static gint   save_dialog              (void);
  276. static void   save_ok_callback         (GtkWidget *widget,
  277.                                         gpointer   data);
  278. static void   save_unit_toggle_update  (GtkWidget *widget,
  279.                                         gpointer   data);
  280.  
  281. GimpPlugInInfo PLUG_IN_INFO =
  282. {
  283.   NULL,  /* init_proc  */
  284.   NULL,  /* quit_proc  */
  285.   query, /* query_proc */
  286.   run,   /* run_proc   */
  287. };
  288.  
  289.  
  290. /* The run mode */
  291. static GimpRunModeType l_run_mode;
  292.  
  293. static void compress_packbits (int nin,
  294.                                unsigned char *src,
  295.                                int *nout,
  296.                                unsigned char *dst);
  297.  
  298.  
  299. static guint32 ascii85_buf;
  300. static int ascii85_len = 0;
  301. static int ascii85_linewidth = 0;
  302.  
  303. static void
  304. ascii85_init (void)
  305. {
  306.   ascii85_len = 0;
  307.   ascii85_linewidth = 0;
  308. }
  309.  
  310. static void
  311. ascii85_flush (FILE *ofp)
  312. {
  313.   char c[5];
  314.   int i;
  315.   gboolean zero_case = (ascii85_buf == 0);
  316.   static int max_linewidth = 75;
  317.  
  318.   for (i=4; i >= 0; i--)
  319.     {
  320.       c[i] = (ascii85_buf % 85) + '!';
  321.       ascii85_buf /= 85;
  322.     }
  323.   /* check for special case: "!!!!!" becomes "z", but only if not
  324.    * at end of data. */
  325.   if (zero_case && (ascii85_len == 4))
  326.     {
  327.       if (ascii85_linewidth >= max_linewidth)
  328.       {
  329.         putc ('\n', ofp);
  330.         ascii85_linewidth = 0;
  331.       }
  332.       putc ('z', ofp);
  333.       ascii85_linewidth++;
  334.     }
  335.   else
  336.     {
  337.       for (i=0; i < ascii85_len+1; i++)
  338.       {
  339.         if ((ascii85_linewidth >= max_linewidth) && (c[i] != '%'))
  340.         {
  341.           putc ('\n', ofp);
  342.           ascii85_linewidth = 0;
  343.         }
  344.     putc (c[i], ofp);
  345.         ascii85_linewidth++;
  346.       }
  347.     }
  348.  
  349.   ascii85_len = 0;
  350.   ascii85_buf = 0;
  351. }
  352.  
  353. static inline void
  354. ascii85_out (unsigned char byte, FILE *ofp)
  355. {
  356.   if (ascii85_len == 4)
  357.     ascii85_flush (ofp);
  358.  
  359.   ascii85_buf <<= 8;
  360.   ascii85_buf |= byte;
  361.   ascii85_len++;
  362. }
  363.  
  364. static void
  365. ascii85_nout (int n, unsigned char *uptr, FILE *ofp)
  366. {
  367.  while (n-- > 0)
  368.  {
  369.    ascii85_out (*uptr, ofp);
  370.    uptr++;
  371.  }
  372. }
  373.  
  374. static void
  375. ascii85_done (FILE *ofp)
  376. {
  377.   if (ascii85_len)
  378.     {
  379.       /* zero any unfilled buffer portion, then flush */
  380.       ascii85_buf <<= (8 * (4-ascii85_len));
  381.       ascii85_flush (ofp);
  382.     }
  383.  
  384.   putc ('~', ofp);
  385.   putc ('>', ofp);
  386.   putc ('\n', ofp);
  387. }
  388.  
  389.  
  390. static void
  391. compress_packbits (int nin,
  392.                    unsigned char *src,
  393.                    int *nout,
  394.                    unsigned char *dst)
  395.  
  396. {register unsigned char c;
  397.  int nrepeat, nliteral;
  398.  unsigned char *run_start;
  399.  unsigned char *start_dst = dst;
  400.  unsigned char *last_literal = NULL;
  401.  
  402.  for (;;)
  403.  {
  404.    if (nin <= 0) break;
  405.  
  406.    run_start = src;
  407.    c = *run_start;
  408.  
  409.    /* Search repeat bytes */
  410.    if ((nin > 1) && (c == src[1]))
  411.    {
  412.      nrepeat = 1;
  413.      nin -= 2;
  414.      src += 2;
  415.      while ((nin > 0) && (c == *src))
  416.      {
  417.        nrepeat++;
  418.        src++;
  419.        nin--;
  420.        if (nrepeat == 127) break; /* Maximum repeat */
  421.      }
  422.  
  423.      /* Add two-byte repeat to last literal run ? */
  424.      if (   (nrepeat == 1)
  425.          && (last_literal != NULL) && (((*last_literal)+1)+2 <= 128))
  426.      {
  427.        *last_literal += 2;
  428.        *(dst++) = c;
  429.        *(dst++) = c;
  430.        continue;
  431.      }
  432.  
  433.      /* Add repeat run */
  434.      *(dst++) = (unsigned char)((-nrepeat) & 0xff);
  435.      *(dst++) = c;
  436.      last_literal = NULL;
  437.      continue;
  438.    }
  439.    /* Search literal bytes */
  440.    nliteral = 1;
  441.    nin--;
  442.    src++;
  443.  
  444.    for (;;)
  445.    {
  446.      if (nin <= 0) break;
  447.  
  448.      if ((nin >= 2) && (src[0] == src[1])) /* A two byte repeat ? */
  449.        break;
  450.  
  451.      nliteral++;
  452.      nin--;
  453.      src++;
  454.      if (nliteral == 128) break; /* Maximum literal run */
  455.    }
  456.  
  457.    /* Could be added to last literal run ? */
  458.    if ((last_literal != NULL) && (((*last_literal)+1)+nliteral <= 128))
  459.    {
  460.      *last_literal += nliteral;
  461.    }
  462.    else
  463.    {
  464.      last_literal = dst;
  465.      *(dst++) = (unsigned char)(nliteral-1);
  466.    }
  467.    while (nliteral-- > 0) *(dst++) = *(run_start++);
  468.  }
  469.  *nout = dst - start_dst;
  470. }
  471.  
  472.  
  473. typedef struct
  474. {
  475.   long eol;
  476.   long begin_data;
  477. } PS_DATA_POS;
  478.  
  479. static PS_DATA_POS ps_data_pos = { 0, 0 };
  480.  
  481. static void
  482. ps_begin_data (FILE *ofp)
  483.  
  484. {
  485.                    /* %%BeginData: 123456789012 ASCII Bytes */
  486.  fprintf (ofp, "%s", "%%BeginData:                         ");
  487.  fflush (ofp);
  488.  ps_data_pos.eol = ftell (ofp);
  489.  fprintf (ofp, "\n");
  490.  fflush (ofp);
  491.  ps_data_pos.begin_data = ftell (ofp);
  492. }
  493.  
  494. static void
  495. ps_end_data (FILE *ofp)
  496.  
  497. {long end_data;
  498.  char s[64];
  499.  
  500.  if ((ps_data_pos.begin_data > 0) && (ps_data_pos.eol > 0))
  501.  {
  502.    fflush (ofp);
  503.    end_data = ftell (ofp);
  504.    if (end_data > 0)
  505.    {
  506.      sprintf (s, "%ld ASCII Bytes", end_data-ps_data_pos.begin_data);
  507.      if (fseek (ofp, ps_data_pos.eol - strlen (s), SEEK_SET) == 0)
  508.      {
  509.        fprintf (ofp, "%s", s);
  510.        fseek (ofp, 0, SEEK_END);
  511.      }
  512.    }
  513.  }
  514.  fprintf (ofp, "%s\n", "%%EndData");
  515. }
  516.  
  517.  
  518. MAIN ()
  519.  
  520. static void
  521. query (void)
  522. {
  523.   static GimpParamDef load_args[] =
  524.   {
  525.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  526.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  527.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to load" }
  528.   };
  529.   static GimpParamDef load_return_vals[] =
  530.   {
  531.     { GIMP_PDB_IMAGE, "image", "Output image" },
  532.   };
  533.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  534.   static gint nload_return_vals = (sizeof (load_return_vals) /
  535.                    sizeof (load_return_vals[0]));
  536.  
  537.   static GimpParamDef set_load_args[] =
  538.   {
  539.     { GIMP_PDB_INT32, "resolution", "Resolution to interprete image (dpi)" },
  540.     { GIMP_PDB_INT32, "width", "Desired width" },
  541.     { GIMP_PDB_INT32, "height", "Desired height" },
  542.     { GIMP_PDB_INT32, "check_bbox", "0: Use width/height, 1: Use BoundingBox" },
  543.     { GIMP_PDB_STRING, "pages", "Pages to load (e.g.: 1,3,5-7)" },
  544.     { GIMP_PDB_INT32, "coloring", "4: b/w, 5: grey, 6: colour image, 7: automatic" },
  545.     { GIMP_PDB_INT32, "TextAlphaBits", "1, 2, or 4" },
  546.     { GIMP_PDB_INT32, "GraphicsAlphaBits", "1, 2, or 4" }
  547.   };
  548.   static gint nset_load_args = (sizeof (set_load_args) /
  549.                 sizeof (set_load_args[0]));
  550.  
  551.   static GimpParamDef save_args[] =
  552.   {
  553.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  554.     { GIMP_PDB_IMAGE, "image", "Input image" },
  555.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  556.     { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
  557.     { GIMP_PDB_STRING, "raw_filename",
  558.             "The name of the file to save the image in" },
  559.     { GIMP_PDB_FLOAT, "width", "Width of the image in PostScript file (0: use input image size)" },
  560.     { GIMP_PDB_FLOAT, "height", "Height of image in PostScript file (0: use input image size)" },
  561.     { GIMP_PDB_FLOAT, "x_offset", "X-offset to image from lower left corner" },
  562.     { GIMP_PDB_FLOAT, "y_offset", "Y-offset to image from lower left corner" },
  563.     { GIMP_PDB_INT32, "unit", "Unit for width/height/offset. 0: inches, 1: millimeters" },
  564.     { GIMP_PDB_INT32, "keep_ratio", "0: use width/height, 1: keep aspect ratio" },
  565.     { GIMP_PDB_INT32, "rotation", "0, 90, 180, 270" },
  566.     { GIMP_PDB_INT32, "eps_flag", "0: PostScript, 1: Encapsulated PostScript" },
  567.     { GIMP_PDB_INT32, "preview", "0: no preview, >0: max. size of preview" },
  568.     { GIMP_PDB_INT32, "level", "1: PostScript Level 1, 2: PostScript Level 2" }
  569.   };
  570.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  571.  
  572.   gimp_install_procedure ("file_ps_load",
  573.                           "load file of PostScript/PDF file format",
  574.                           "load file of PostScript/PDF file format",
  575.                           "Peter Kirchgessner <peter@kirchgessner.net>",
  576.                           "Peter Kirchgessner",
  577.                           dversio,
  578.                           "<Load>/PostScript",
  579.                           NULL,
  580.                           GIMP_PLUGIN,
  581.                           nload_args, nload_return_vals,
  582.                           load_args, load_return_vals);
  583.  
  584.   gimp_install_procedure ("file_ps_load_setargs",
  585.                           "set additional parameters for procedure file_ps_load",
  586.                           "set additional parameters for procedure file_ps_load",
  587.                           "Peter Kirchgessner <peter@kirchgessner.net>",
  588.                           "Peter Kirchgessner",
  589.                           dversio,
  590.                           NULL,
  591.                           NULL,
  592.                           GIMP_PLUGIN,
  593.                           nset_load_args, 0,
  594.                           set_load_args, NULL);
  595.  
  596.   gimp_install_procedure ("file_ps_save",
  597.                           "save file in PostScript file format",
  598.                           "PostScript saving handles all image types except those with alpha channels.",
  599.                           "Peter Kirchgessner <peter@kirchgessner.net>",
  600.                           "Peter Kirchgessner",
  601.                           dversio,
  602.                           "<Save>/PostScript",
  603.                           "RGB, GRAY, INDEXED",
  604.                           GIMP_PLUGIN,
  605.                           nsave_args, 0,
  606.                           save_args, NULL);
  607.  
  608.   gimp_register_magic_load_handler ("file_ps_load",
  609.                     "ps,eps,pdf",
  610.                     "",
  611.                                     "0,string,%!,0,string,%PDF,0,long,0xc5d0d3c6");
  612.   gimp_register_save_handler       ("file_ps_save",
  613.                     "ps,eps",
  614.                     "");
  615. }
  616.  
  617.  
  618. #ifdef GIMP_HAVE_RESOLUTION_INFO
  619. static void
  620. ps_set_save_size (PSSaveVals *vals,
  621.                   gint32      image_ID)
  622. {
  623.   gdouble  xres, yres, factor, iw, ih;
  624.   guint    width, height;
  625.   GimpUnit unit;
  626.  
  627.   gimp_image_get_resolution (image_ID, &xres, &yres);
  628.   if ((xres < 1e-5) || (yres < 1e-5))
  629.     {
  630.       xres = yres = 72.0;
  631.     }
  632.   /* Calculate size of image in inches */
  633.   width  = gimp_image_width (image_ID);
  634.   height = gimp_image_height (image_ID);
  635.   iw = width  / xres;
  636.   ih = height / yres;
  637.  
  638.   unit = gimp_image_get_unit (image_ID);
  639.   factor = gimp_unit_get_factor (unit);
  640.   if (factor == 0.0254 ||
  641.       factor == 0.254 ||
  642.       factor == 2.54 ||
  643.       factor == 25.4)
  644.     {
  645.       vals->unit_mm = TRUE;
  646.     }
  647.  
  648.   if (vals->unit_mm)
  649.     {
  650.       iw *= 25.4;
  651.       ih *= 25.4;
  652.     }
  653.   vals->width  = iw;
  654.   vals->height = ih;
  655. }
  656. #endif
  657.  
  658. static void
  659. run (gchar   *name,
  660.      gint     nparams,
  661.      GimpParam  *param,
  662.      gint    *nreturn_vals,
  663.      GimpParam **return_vals)
  664. {
  665.   static GimpParam values[2];
  666.   GimpRunModeType  run_mode;
  667.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  668.   gint32        image_ID = -1;
  669.   gint32        drawable_ID = -1;
  670.   gint32        orig_image_ID = -1;
  671.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  672.   gint k;
  673.  
  674.   l_run_mode = run_mode = param[0].data.d_int32;
  675.  
  676.   *nreturn_vals = 1;
  677.   *return_vals  = values;
  678.   values[0].type          = GIMP_PDB_STATUS;
  679.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  680.  
  681.   if (strcmp (name, "file_ps_load") == 0)
  682.     {
  683.       INIT_I18N_UI();
  684.  
  685.       switch (run_mode)
  686.     {
  687.         case GIMP_RUN_INTERACTIVE:
  688.           /*  Possibly retrieve data  */
  689.           gimp_get_data ("file_ps_load", &plvals);
  690.  
  691.           if (! load_dialog ())
  692.         status = GIMP_PDB_CANCEL;
  693.           break;
  694.  
  695.         case GIMP_RUN_NONINTERACTIVE:
  696.           /*  Make sure all the arguments are there!  */
  697.           if (nparams != 3)
  698.             status = GIMP_PDB_CALLING_ERROR;
  699.           else    /* Get additional interpretation arguments */
  700.             gimp_get_data ("file_ps_load", &plvals);
  701.           break;
  702.  
  703.         case GIMP_RUN_WITH_LAST_VALS:
  704.           /* Possibly retrieve data */
  705.           gimp_get_data ("file_ps_load", &plvals);
  706.           break;
  707.  
  708.         default:
  709.           break;
  710.     }
  711.  
  712.       if (status == GIMP_PDB_SUCCESS)
  713.     {
  714.       check_load_vals ();
  715.       image_ID = load_image (param[1].data.d_string);
  716.  
  717.       if (image_ID != -1)
  718.         {
  719.           *nreturn_vals = 2;
  720.           values[1].type         = GIMP_PDB_IMAGE;
  721.           values[1].data.d_image = image_ID;
  722.         }
  723.       else
  724.         {
  725.           status = GIMP_PDB_EXECUTION_ERROR;
  726.         }
  727.     }
  728.  
  729.       /*  Store plvals data  */
  730.       if (status == GIMP_PDB_SUCCESS)
  731.     gimp_set_data ("file_ps_load", &plvals, sizeof (PSLoadVals));
  732.     }
  733.   else if (strcmp (name, "file_ps_save") == 0)
  734.     {
  735.       INIT_I18N_UI();
  736.  
  737.       image_ID = orig_image_ID = param[1].data.d_int32;
  738.       drawable_ID = param[2].data.d_int32;
  739.  
  740.       /* eventually export the image */
  741.       switch (run_mode)
  742.     {
  743.     case GIMP_RUN_INTERACTIVE:
  744.     case GIMP_RUN_WITH_LAST_VALS:
  745.       gimp_ui_init ("ps", FALSE);
  746.       export = gimp_export_image (&image_ID, &drawable_ID, "PS",
  747.                       (GIMP_EXPORT_CAN_HANDLE_RGB |
  748.                        GIMP_EXPORT_CAN_HANDLE_GRAY |
  749.                        GIMP_EXPORT_CAN_HANDLE_INDEXED));
  750.       if (export == GIMP_EXPORT_CANCEL)
  751.         {
  752.           values[0].data.d_status = GIMP_PDB_CANCEL;
  753.           return;
  754.         }
  755.       break;
  756.     default:
  757.       break;
  758.     }
  759.  
  760.       switch (run_mode)
  761.         {
  762.         case GIMP_RUN_INTERACTIVE:
  763.           /*  Possibly retrieve data  */
  764.           gimp_get_data ("file_ps_save", &psvals);
  765.  
  766.           /* About to save an EPS-file ? Switch on eps-flag in dialog */
  767.           k = strlen (param[3].data.d_string);
  768.           if ((k >= 4) && (strcmp (param[3].data.d_string+k-4, ".eps") == 0))
  769.             psvals.eps = 1;
  770.  
  771. #ifdef GIMP_HAVE_RESOLUTION_INFO
  772.           ps_set_save_size (&psvals, orig_image_ID);
  773. #endif
  774.           /*  First acquire information with a dialog  */
  775.           if (! save_dialog ())
  776.             status = GIMP_PDB_CANCEL;
  777.           break;
  778.  
  779.         case GIMP_RUN_NONINTERACTIVE:
  780.           /*  Make sure all the arguments are there!  */
  781.           if (nparams != 15)
  782.         {
  783.           status = GIMP_PDB_CALLING_ERROR;
  784.         }
  785.           else
  786.         {
  787.           psvals.width        = param[5].data.d_float;
  788.           psvals.height       = param[6].data.d_float;
  789.           psvals.x_offset     = param[7].data.d_float;
  790.           psvals.y_offset     = param[8].data.d_float;
  791.           psvals.unit_mm      = (param[9].data.d_int32 != 0);
  792.           psvals.keep_ratio   = (param[10].data.d_int32 != 0);
  793.           psvals.rotate       = param[11].data.d_int32;
  794.           psvals.eps          = param[12].data.d_int32;
  795.           psvals.preview      = (param[13].data.d_int32 != 0);
  796.           psvals.preview_size = param[13].data.d_int32;
  797.           psvals.level        = param[14].data.d_int32;
  798.         }
  799.           break;
  800.  
  801.         case GIMP_RUN_WITH_LAST_VALS:
  802.           /*  Possibly retrieve data  */
  803.           gimp_get_data ("file_ps_save", &psvals);
  804.           break;
  805.  
  806.         default:
  807.           break;
  808.         }
  809.  
  810.       if (status == GIMP_PDB_SUCCESS)
  811.     {
  812. #ifdef GIMP_HAVE_RESOLUTION_INFO
  813.       if ((psvals.width == 0.0) || (psvals.height == 0.0))
  814.         ps_set_save_size (&psvals, orig_image_ID);
  815. #endif
  816.       check_save_vals ();
  817.       if (save_image (param[3].data.d_string, image_ID, drawable_ID))
  818.         {
  819.           /*  Store psvals data  */
  820.           gimp_set_data ("file_ps_save", &psvals, sizeof (PSSaveVals));
  821.         }
  822.       else
  823.         {
  824.           status = GIMP_PDB_EXECUTION_ERROR;
  825.         }
  826.     }
  827.  
  828.       if (export == GIMP_EXPORT_EXPORT)
  829.     gimp_image_delete (image_ID);
  830.     }
  831.   else if (strcmp (name, "file_ps_load_setargs") == 0)
  832.     {
  833.       /*  Make sure all the arguments are there!  */
  834.       if (nparams != 8)
  835.     {
  836.       status = GIMP_PDB_CALLING_ERROR;
  837.     }
  838.       else
  839.     {
  840.       plvals.resolution = param[0].data.d_int32;
  841.       plvals.width      = param[1].data.d_int32;
  842.       plvals.height     = param[2].data.d_int32;
  843.       plvals.use_bbox   = param[3].data.d_int32;
  844.       if (param[4].data.d_string != NULL)
  845.         strncpy (plvals.pages, param[4].data.d_string,
  846.              sizeof (plvals.pages));
  847.       else
  848.         plvals.pages[0] = '\0';
  849.       plvals.pages[sizeof (plvals.pages) - 1] = '\0';
  850.       plvals.pnm_type      = param[5].data.d_int32;
  851.       plvals.textalpha     = param[6].data.d_int32;
  852.       plvals.graphicsalpha = param[7].data.d_int32;
  853.       check_load_vals ();
  854.       gimp_set_data ("file_ps_load", &plvals, sizeof (PSLoadVals));
  855.     }
  856.     }
  857.   else
  858.     {
  859.       status = GIMP_PDB_CALLING_ERROR;
  860.     }
  861.  
  862.   values[0].data.d_status = status;
  863. }
  864.  
  865.  
  866. static gint32
  867. load_image (gchar *filename)
  868. {
  869.   gint32 image_ID, *image_list, *nl;
  870.   guint page_count;
  871.   FILE *ifp;
  872.   char *temp;
  873.   int  llx, lly, urx, ury;
  874.   int  k, n_images, max_images, max_pagenum;
  875.   int  is_epsf;
  876.  
  877. #ifdef PS_DEBUG
  878.   g_print ("load_image:\n resolution = %d\n", plvals.resolution);
  879.   g_print (" %dx%d pixels\n", plvals.width, plvals.height);
  880.   g_print (" BoundingBox: %d\n", plvals.use_bbox);
  881.   g_print (" Colouring: %d\n", plvals.pnm_type);
  882.   g_print (" TextAlphaBits: %d\n", plvals.textalpha);
  883.   g_print (" GraphicsAlphaBits: %d\n", plvals.graphicsalpha);
  884. #endif
  885.  
  886.   /* Try to see if PostScript file is available */
  887.   ifp = fopen (filename, "r");
  888.   if (ifp == NULL)
  889.     {
  890.       g_message (_("PS: can't open file for reading"));
  891.       return (-1);
  892.     }
  893.   fclose (ifp);
  894.  
  895.   if (l_run_mode != GIMP_RUN_NONINTERACTIVE)
  896.     {
  897.       temp = g_strdup_printf (_("Interpreting and Loading %s:"), filename);
  898.       gimp_progress_init (temp);
  899.       g_free (temp);
  900.     }
  901.  
  902.   ifp = ps_open (filename, &plvals, &llx, &lly, &urx, &ury, &is_epsf);
  903.   if (!ifp)
  904.     {
  905.       g_message (_("PS: can't interprete file"));
  906.       return (-1);
  907.     }
  908.  
  909.   image_list = (gint32 *)g_malloc (10 * sizeof (gint32));
  910.   n_images = 0;
  911.   max_images = 10;
  912.  
  913.   max_pagenum = 9999;  /* Try to get the maximum pagenumber to read */
  914.   if (is_epsf) max_pagenum = 1;
  915.   if (!page_in_list (plvals.pages, max_pagenum)) /* Is there a limit in list ? */
  916.     {
  917.       max_pagenum = -1;
  918.       for (temp = plvals.pages; *temp != '\0'; temp++)
  919.     {
  920.       if ((*temp < '0') || (*temp > '9')) continue; /* Search next digit */
  921.       sscanf (temp, "%d", &k);
  922.       if (k > max_pagenum) max_pagenum = k;
  923.       while ((*temp >= '0') && (*temp <= '9')) temp++;
  924.       temp--;
  925.     }
  926.       if (max_pagenum < 1) max_pagenum = 9999;
  927.     }
  928.  
  929.   /* Load all images */
  930.   for (page_count = 1; page_count <= max_pagenum; page_count++)
  931.     {
  932.       if (page_in_list (plvals.pages, page_count))
  933.     {
  934.       image_ID = load_ps (filename, page_count, ifp, llx, lly, urx, ury);
  935.       if (image_ID == -1) break;
  936. #ifdef GIMP_HAVE_RESOLUTION_INFO
  937.       gimp_image_set_resolution (image_ID,
  938.                      (double) plvals.resolution,
  939.                      (double) plvals.resolution);
  940. #endif
  941.       if (n_images == max_images)
  942.         {
  943.           nl = (gint32 *) g_realloc (image_list,
  944.                      (max_images+10)*sizeof (gint32));
  945.           if (nl == NULL) break;
  946.           image_list = nl;
  947.           max_images += 10;
  948.         }
  949.       image_list[n_images++] = image_ID;
  950.     }
  951.       else  /* Skip an image */
  952.     {
  953.       image_ID = skip_ps (ifp);
  954.       if (image_ID == -1) break;
  955.     }
  956.     }
  957.   ps_close (ifp);
  958.  
  959.   /* Display images in reverse order. The last will be displayed by GIMP itself*/
  960.   if (l_run_mode != GIMP_RUN_NONINTERACTIVE)
  961.     {
  962.       for (k = n_images-1; k >= 1; k--)
  963.     gimp_display_new (image_list[k]);
  964.     }
  965.  
  966.   image_ID = (n_images > 0) ? image_list[0] : -1;
  967.   g_free (image_list);
  968.  
  969.   return (image_ID);
  970. }
  971.  
  972.  
  973. static gint
  974. save_image (gchar  *filename,
  975.             gint32  image_ID,
  976.             gint32  drawable_ID)
  977. {
  978.   FILE* ofp;
  979.   GimpImageType drawable_type;
  980.   gint retval;
  981.   char *temp = ident; /* Just to satisfy lint/gcc */
  982.  
  983.   /* initialize */
  984.  
  985.   retval = 0;
  986.  
  987.   drawable_type = gimp_drawable_type (drawable_ID);
  988.  
  989.   /*  Make sure we're not saving an image with an alpha channel  */
  990.   if (gimp_drawable_has_alpha (drawable_ID))
  991.     {
  992.       g_message (_("PostScript save cannot handle images with alpha channels"));
  993.       return FALSE;
  994.     }
  995.  
  996.   switch (drawable_type)
  997.     {
  998.     case GIMP_INDEXED_IMAGE:
  999.     case GIMP_GRAY_IMAGE:
  1000.     case GIMP_RGB_IMAGE:
  1001.       break;
  1002.     default:
  1003.       g_message (_("PS: cannot operate on unknown image types"));
  1004.       return (FALSE);
  1005.       break;
  1006.     }
  1007.  
  1008.   /* Open the output file. */
  1009.   ofp = fopen (filename, "wb");
  1010.   if (!ofp)
  1011.     {
  1012.       g_message (_("PS: can't open file for writing"));
  1013.       return (FALSE);
  1014.     }
  1015.  
  1016.   if (l_run_mode != GIMP_RUN_NONINTERACTIVE)
  1017.     {
  1018.       temp = g_strdup_printf (_("Saving %s:"), filename);
  1019.       gimp_progress_init (temp);
  1020.       g_free (temp);
  1021.     }
  1022.  
  1023.   save_ps_header (ofp, filename);
  1024.  
  1025.   if (drawable_type == GIMP_GRAY_IMAGE)
  1026.     retval = save_gray (ofp, image_ID, drawable_ID);
  1027.   else if (drawable_type == GIMP_INDEXED_IMAGE)
  1028.     retval = save_index (ofp, image_ID, drawable_ID);
  1029.   else if (drawable_type == GIMP_RGB_IMAGE)
  1030.     retval = save_rgb (ofp, image_ID, drawable_ID);
  1031.  
  1032.   save_ps_trailer (ofp);
  1033.  
  1034.   fclose (ofp);
  1035.  
  1036.   return (retval);
  1037. }
  1038.  
  1039.  
  1040. /* Check (and correct) the load values plvals */
  1041. static void
  1042. check_load_vals (void)
  1043. {
  1044.   if (plvals.resolution < 5)
  1045.     plvals.resolution = 5;
  1046.   else if (plvals.resolution > 1440)
  1047.     plvals.resolution = 1440;
  1048.  
  1049.   if (plvals.width < 2)
  1050.     plvals.width = 2;
  1051.   if (plvals.height < 2)
  1052.     plvals.height = 2;
  1053.   plvals.use_bbox = (plvals.use_bbox != 0);
  1054.   if (plvals.pages[0] == '\0')
  1055.     strcpy (plvals.pages, "1-99");
  1056.   if ((plvals.pnm_type < 4) || (plvals.pnm_type > 7))
  1057.     plvals.pnm_type = 6;
  1058.   if (   (plvals.textalpha != 1) && (plvals.textalpha != 2)
  1059.       && (plvals.textalpha != 4))
  1060.     plvals.textalpha = 1;
  1061.   if (   (plvals.graphicsalpha != 1) && (plvals.graphicsalpha != 2)
  1062.       && (plvals.graphicsalpha != 4))
  1063.     plvals.graphicsalpha = 1;
  1064. }
  1065.  
  1066.  
  1067. /* Check (and correct) the save values psvals */
  1068. static void
  1069. check_save_vals (void)
  1070. {
  1071.   int i;
  1072.  
  1073.   i = psvals.rotate;
  1074.   if ((i != 0) && (i != 90) && (i != 180) && (i != 270))
  1075.     psvals.rotate = 90;
  1076.   if (psvals.preview_size <= 0)
  1077.     psvals.preview = FALSE;
  1078. }
  1079.  
  1080.  
  1081. /* Check if a page is in a given list */
  1082. static gint
  1083. page_in_list (gchar *list,
  1084.               guint  page_num)
  1085. {
  1086.   char tmplist[STR_LENGTH], *c0, *c1;
  1087.   int state, start_num, end_num;
  1088. #define READ_STARTNUM  0
  1089. #define READ_ENDNUM    1
  1090. #define CHK_LIST(a,b,c) {int low=(a),high=(b),swp; \
  1091.   if ((low>0) && (high>0)) { \
  1092.   if (low>high) {swp=low; low=high; high=swp;} \
  1093.   if ((low<=(c))&&(high>=(c))) return (1); } }
  1094.  
  1095.   if ((list == NULL) || (*list == '\0')) return (1);
  1096.  
  1097.   strncpy (tmplist, list, STR_LENGTH);
  1098.   tmplist[STR_LENGTH-1] = '\0';
  1099.  
  1100.   c0 = c1 = tmplist;
  1101.   while (*c1)    /* Remove all whitespace and break on unsupported characters */
  1102.     {
  1103.       if ((*c1 >= '0') && (*c1 <= '9'))
  1104.     {
  1105.       *(c0++) = *c1;
  1106.     }
  1107.       else if ((*c1 == '-') || (*c1 == ','))
  1108.     { /* Try to remove double occurances of these characters */
  1109.       if (c0 == tmplist)
  1110.         {
  1111.           *(c0++) = *c1;
  1112.         }
  1113.       else
  1114.         {
  1115.           if (*(c0-1) != *c1)
  1116.         *(c0++) = *c1;
  1117.         }
  1118.     }
  1119.       else break;
  1120.       c1++;
  1121.     }
  1122.   if (c0 == tmplist) return (1);
  1123.   *c0 = '\0';
  1124.  
  1125.   /* Now we have a comma separated list like 1-4-1,-3,1- */
  1126.  
  1127.   start_num = end_num = -1;
  1128.   state = READ_STARTNUM;
  1129.   for (c0 = tmplist; *c0 != '\0'; c0++)
  1130.     {
  1131.       switch (state)
  1132.     {
  1133.     case READ_STARTNUM:
  1134.       if (*c0 == ',')
  1135.         {
  1136.           if ((start_num > 0) && (start_num == (int)page_num)) return (-1);
  1137.           start_num = -1;
  1138.         }
  1139.       else if (*c0 == '-')
  1140.         {
  1141.           if (start_num < 0) start_num = 1;
  1142.           state = READ_ENDNUM;
  1143.         }
  1144.       else /* '0' - '9' */
  1145.         {
  1146.           if (start_num < 0) start_num = 0;
  1147.           start_num *= 10;
  1148.           start_num += *c0 - '0';
  1149.         }
  1150.       break;
  1151.  
  1152.     case READ_ENDNUM:
  1153.       if (*c0 == ',')
  1154.         {
  1155.           if (end_num < 0) end_num = 9999;
  1156.           CHK_LIST (start_num, end_num, (int)page_num);
  1157.           start_num = end_num = -1;
  1158.           state = READ_STARTNUM;
  1159.         }
  1160.       else if (*c0 == '-')
  1161.         {
  1162.           CHK_LIST (start_num, end_num, (int)page_num);
  1163.           start_num = end_num;
  1164.           end_num = -1;
  1165.         }
  1166.       else /* '0' - '9' */
  1167.         {
  1168.           if (end_num < 0) end_num = 0;
  1169.           end_num *= 10;
  1170.           end_num += *c0 - '0';
  1171.         }
  1172.       break;
  1173.     }
  1174.     }
  1175.   if (state == READ_STARTNUM)
  1176.     {
  1177.       if (start_num > 0)
  1178.     return (start_num == (int)page_num);
  1179.     }
  1180.   else
  1181.     {
  1182.       if (end_num < 0) end_num = 9999;
  1183.       CHK_LIST (start_num, end_num, (int)page_num);
  1184.     }
  1185.   return (0);
  1186. #undef CHK_LIST
  1187. }
  1188.  
  1189.  
  1190. /* A function like fgets, but treats single CR-character as line break. */
  1191. /* As a line break the newline-character is returned. */
  1192. static char *psfgets (char *s, int size, FILE *stream)
  1193.  
  1194. {int c;
  1195.  char *sptr = s;
  1196.  
  1197.  if (size <= 0) return NULL;
  1198.  if (size == 1)
  1199.  {
  1200.    *s = '\0';
  1201.    return NULL;
  1202.  }
  1203.  c = getc (stream);
  1204.  if (c == EOF) return NULL;
  1205.  
  1206.  for (;;)
  1207.  {
  1208.    /* At this point we have space in sptr for at least two characters */
  1209.    if (c == '\n')    /* Got end of line (UNIX line end) ? */
  1210.    {
  1211.      *(sptr++) = '\n';
  1212.      break;
  1213.    }
  1214.    else if (c == '\r')  /* Got a carriage return. Check next charcater */
  1215.    {
  1216.      c = getc (stream);
  1217.      if ((c == EOF) || (c == '\n')) /* EOF or DOS line end ? */
  1218.      {
  1219.        *(sptr++) = '\n';  /* Return UNIX line end */
  1220.        break;
  1221.      }
  1222.      else  /* Single carriage return. Return UNIX line end. */
  1223.      {
  1224.        ungetc (c, stream);  /* Save the extra character */
  1225.        *(sptr++) = '\n';
  1226.        break;
  1227.      }
  1228.    }
  1229.    else   /* no line end character */
  1230.    {
  1231.      *(sptr++) = (char)c;
  1232.      size--;
  1233.    }
  1234.    if (size == 1) break;  /* Only space for the nul-character ? */
  1235.    c = getc (stream);
  1236.    if (c == EOF) break;
  1237.  }
  1238.  *sptr = '\0';
  1239.  return s;
  1240. }
  1241.  
  1242.  
  1243. /* Get the BoundingBox of a PostScript file. On success, 0 is returned. */
  1244. /* On failure, -1 is returned. */
  1245. static gint
  1246. get_bbox (gchar *filename,
  1247.           gint  *x0,
  1248.           gint  *y0,
  1249.           gint  *x1,
  1250.           gint  *y1)
  1251. {
  1252.   char line[1024], *src;
  1253.   FILE *ifp;
  1254.   int retval = -1;
  1255.  
  1256.   ifp = fopen (filename, "rb");
  1257.   if (ifp == NULL) return (-1);
  1258.  
  1259.   for (;;)
  1260.     {
  1261.       if (psfgets (line, sizeof (line)-1, ifp) == NULL) break;
  1262.       if ((line[0] != '%') || (line[1] != '%')) continue;
  1263.       src = &(line[2]);
  1264.       while ((*src == ' ') || (*src == '\t')) src++;
  1265.       if (strncmp (src, "BoundingBox", 11) != 0) continue;
  1266.       src += 11;
  1267.       while ((*src == ' ') || (*src == '\t') || (*src == ':')) src++;
  1268.       if (strncmp (src, "(atend)", 7) == 0) continue;
  1269.       if (sscanf (src, "%d%d%d%d", x0, y0, x1, y1) == 4)
  1270.     retval = 0;
  1271.       break;
  1272.     }
  1273.   fclose (ifp);
  1274.   return (retval);
  1275. }
  1276.  
  1277. static gchar *pnmfile;
  1278. #ifdef G_OS_WIN32
  1279. static gchar *indirfile = NULL;
  1280. #endif
  1281.  
  1282. /* Open the PostScript file. On failure, NULL is returned. */
  1283. /* The filepointer returned will give a PNM-file generated */
  1284. /* by the PostScript-interpreter. */
  1285. static FILE *
  1286. ps_open (gchar            *filename,
  1287.          const PSLoadVals *loadopt,
  1288.          gint             *llx,
  1289.          gint             *lly,
  1290.          gint             *urx,
  1291.          gint             *ury,
  1292.          gint             *is_epsf)
  1293. {
  1294.   char *cmd, *gs, *gs_opts, *driver, *quoted_fn, *fnbuf = NULL;
  1295.   FILE *fd_popen;
  1296.   int width, height, resolution;
  1297.   int x0, y0, x1, y1;
  1298.   int offx = 0, offy = 0;
  1299.   int is_pdf, maybe_epsf = 0;
  1300.   char TextAlphaBits[64], GraphicsAlphaBits[64], geometry[32];
  1301.   char offset[32];
  1302.  
  1303.   resolution = loadopt->resolution;
  1304.   *llx = *lly = 0;
  1305.   width = loadopt->width;
  1306.   height = loadopt->height;
  1307.   *urx = width-1;
  1308.   *ury = height-1;
  1309.  
  1310.   /* Check if the file is a PDF. For PDF, we cant set geometry */
  1311.   is_pdf = 0;
  1312.   /* Check if it is a EPS-file */
  1313.   *is_epsf = 0;
  1314.   fd_popen = fopen (filename, "rb");
  1315.   if (fd_popen != NULL)
  1316.     {
  1317.       char hdr[512];
  1318.  
  1319.       fread (hdr, 1, sizeof(hdr), fd_popen);
  1320.       is_pdf = (strncmp (hdr, "%PDF", 4) == 0);
  1321.  
  1322.       if (!is_pdf)  /* Check for EPSF */
  1323.       {char *adobe, *epsf;
  1324.        int ds = 0;
  1325.        static unsigned char doseps[5] = { 0xc5, 0xd0, 0xd3, 0xc6, 0 };
  1326.  
  1327.         hdr[sizeof(hdr)-1] = '\0';
  1328.         adobe = strstr (hdr, "PS-Adobe-");
  1329.         epsf = strstr (hdr, "EPSF-");
  1330.         if ((adobe != NULL) && (epsf != NULL))
  1331.           ds = epsf - adobe;
  1332.         *is_epsf = ((ds >= 11) && (ds <= 15));
  1333.         /* Illustrator uses negative values in BoundingBox without marking */
  1334.         /* files as EPSF. Try to handle that. */
  1335.         maybe_epsf = (strstr (hdr, "%%Creator: Adobe Illustrator(R) 8.0") != 0);
  1336.  
  1337.         /* Check DOS EPS binary file */
  1338.         if ((!*is_epsf) && (strncmp (hdr, (char *)doseps, 4) == 0))
  1339.           *is_epsf = 1;
  1340.       }
  1341.       fclose (fd_popen);
  1342.     }
  1343.  
  1344.   if ((!is_pdf) && (loadopt->use_bbox))    /* Try the BoundingBox ? */
  1345.     {
  1346.       if (get_bbox (filename, &x0, &y0, &x1, &y1) == 0)
  1347.         {
  1348.           if (maybe_epsf && ((x0 < 0) || (y0 < 0)))
  1349.             *is_epsf = 1;
  1350.  
  1351.           if (*is_epsf)  /* Handle negative BoundingBox for EPSF */
  1352.             {
  1353.               offx = -x0; x1 += offx; x0 += offx;
  1354.               offy = -y0; y1 += offy; y0 += offy;
  1355.             }
  1356.           if ((x0 >= 0) && (y0 >= 0) && (x1 > x0) && (y1 > y0))
  1357.             {
  1358.                *llx = (int)((x0/72.0) * resolution + 0.0001);
  1359.                *lly = (int)((y0/72.0) * resolution + 0.0001);
  1360.                *urx = (int)((x1/72.0) * resolution + 0.5);
  1361.                *ury = (int)((y1/72.0) * resolution + 0.5);
  1362.                width = *urx;
  1363.                height = *ury;
  1364.             }
  1365.         }
  1366.     }
  1367.   if (loadopt->pnm_type == 4) driver = "pbmraw";
  1368.   else if (loadopt->pnm_type == 5) driver = "pgmraw";
  1369.   else if (loadopt->pnm_type == 7) driver = "pnmraw";
  1370.   else driver = "ppmraw";
  1371.  
  1372. #ifdef USE_REAL_OUTPUTFILE
  1373.   /* For instance, the Win32 port of ghostscript doesn't work correctly when
  1374.    * using standard output as output file.
  1375.    * Thus, use a real output file.
  1376.    */
  1377.   pnmfile = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "p%lx",
  1378.                  g_get_tmp_dir (), getpid ());
  1379. #else
  1380.   pnmfile = "-";
  1381. #endif
  1382.  
  1383.   gs = getenv ("GS_PROG");
  1384.   if (gs == NULL)
  1385.     gs = DEFAULT_GS_PROG;
  1386.  
  1387.   quoted_fn = g_shell_quote (filename);
  1388.  
  1389.   gs_opts = getenv ("GS_OPTIONS");
  1390.   if (gs_opts == NULL)
  1391.     gs_opts = "-dSAFER";
  1392.   else
  1393.     gs_opts = "";  /* Ghostscript will add these options */
  1394.  
  1395.   TextAlphaBits[0] = GraphicsAlphaBits[0] = geometry[0] = '\0';
  1396.   offset[0] = '\0';
  1397.  
  1398.   /* Offset command for gs to get image part with negative x/y-coord. */
  1399.   if ((offx != 0) || (offy != 0))
  1400.     sprintf (offset, "-c %d %d translate ", offx, offy);
  1401.  
  1402.   /* Antialiasing not available for PBM-device */
  1403.   if ((loadopt->pnm_type != 4) && (loadopt->textalpha != 1))
  1404.     sprintf (TextAlphaBits, "-dTextAlphaBits=%d ", (int)loadopt->textalpha);
  1405.  
  1406.   if ((loadopt->pnm_type != 4) && (loadopt->graphicsalpha != 1))
  1407.     sprintf (GraphicsAlphaBits, "-dGraphicsAlphaBits=%d ",
  1408.          (int)loadopt->graphicsalpha);
  1409.  
  1410.   if (!is_pdf)    /* For PDF, we cant set geometry */
  1411.     sprintf (geometry,"-g%dx%d ", width, height);
  1412.  
  1413.   cmd = g_strdup_printf ("%s -sDEVICE=%s -r%d %s%s%s-q -dNOPAUSE %s "
  1414.                          "-sOutputFile=%s %s-f %s %s-c quit",
  1415.              gs, driver, resolution, geometry,
  1416.              TextAlphaBits, GraphicsAlphaBits,
  1417.              gs_opts, pnmfile, offset, quoted_fn,
  1418.                          *is_epsf ? "-c showpage " : "");
  1419. #ifdef PS_DEBUG
  1420.   g_print ("Going to start ghostscript with:\n%s\n", cmd);
  1421. #endif
  1422.  
  1423. #ifndef USE_REAL_OUTPUTFILE
  1424.   /* Start the command and use a pipe for reading the PNM-file. */
  1425. #ifndef __EMX__
  1426.   fd_popen = popen (cmd, "r");
  1427. #else
  1428.   fd_popen = popen (cmd, "rb");
  1429. #endif
  1430. #else
  1431.   /* If someone does not like the pipe (or it does not work), just start */
  1432.   /* ghostscript with a real outputfile. When ghostscript has finished,  */
  1433.   /* open the outputfile and return its filepointer. But be sure         */
  1434.   /* to close and remove the file within ps_close().                     */
  1435. #ifdef G_OS_WIN32
  1436.   /* Work around braindead command line length limit.
  1437.    * Hmm, I wonder if this is necessary, but it doesn't harm...
  1438.    */
  1439.   if (strlen (cmd) >= 100)
  1440.     {
  1441.       FILE *indf;
  1442.       indirfile = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "i%lx",
  1443.                    g_get_tmp_dir (), getpid ());
  1444.       indf = fopen (indirfile, "w");
  1445.       fprintf (indf, "%s -sDEVICE=%s -r%d %s%s%s-q -dNOPAUSE %s "
  1446.                  "-sOutputFile=%s %s-f %s %s-c quit\n",
  1447.            gs, driver, resolution, geometry,
  1448.            TextAlphaBits, GraphicsAlphaBits,
  1449.            gs_opts, pnmfile, offset, filename,
  1450.            *is_epsf ? "-c showpage " : "");
  1451.       sprintf (cmd, "%s @%s", gs, indirfile);
  1452.       fclose (indf);
  1453.     }
  1454. #endif
  1455.   system (cmd);
  1456.   fd_popen = fopen (pnmfile, "rb");
  1457. #endif
  1458.   g_free (cmd);
  1459.   g_free (fnbuf);
  1460.   g_free (quoted_fn);
  1461.  
  1462.   return (fd_popen);
  1463. }
  1464.  
  1465.  
  1466. /* Close the PNM-File of the PostScript interpreter */
  1467. static void
  1468. ps_close (FILE *ifp)
  1469. {
  1470. #ifndef USE_REAL_OUTPUTFILE
  1471.  
  1472.   /* Even if we dont want all images, we have to read the pipe until EOF. */
  1473.   /* Otherwise the subprocess and therefore pclose() may not finish. */
  1474.   while (getc (ifp) != EOF) ;
  1475.  
  1476.   /* Finish reading from pipe. */
  1477.   pclose (ifp);
  1478. #else
  1479.  /* If a real outputfile was used, close the file and remove it. */
  1480.   fclose (ifp);
  1481.   unlink (pnmfile);
  1482. #ifdef G_OS_WIN32
  1483.   if (indirfile != NULL)
  1484.     unlink (indirfile);
  1485. #endif
  1486. #endif
  1487. }
  1488.  
  1489.  
  1490. /* Read the header of a raw PNM-file and return type (4-6) or -1 on failure */
  1491. static gint
  1492. read_pnmraw_type (FILE *ifp,
  1493.                   gint *width,
  1494.                   gint *height,
  1495.                   gint *maxval)
  1496. {
  1497.   register int frst, scnd, thrd;
  1498.   gint pnmtype;
  1499.   char line[1024];
  1500.  
  1501.   /* GhostScript may write some informational messages infront of the header. */
  1502.   /* We are just looking at a Px\n in the input stream. */
  1503.   frst = getc (ifp);
  1504.   scnd = getc (ifp);
  1505.   thrd = getc (ifp);
  1506.   for (;;)
  1507.     {
  1508.       if (thrd == EOF) return (-1);
  1509. #if defined (__EMX__) || defined (WIN32)
  1510.       if (thrd == '\r') thrd = getc (ifp);
  1511. #endif
  1512.       if ((thrd == '\n') && (frst == 'P') && (scnd >= '1') && (scnd <= '6'))
  1513.     break;
  1514.       frst = scnd;
  1515.       scnd = thrd;
  1516.       thrd = getc (ifp);
  1517.     }
  1518.   pnmtype = scnd - '0';
  1519.   /* We dont use the ASCII-versions */
  1520.   if ((pnmtype >= 1) && (pnmtype <= 3)) return (-1);
  1521.  
  1522.   /* Read width/height */
  1523.   for (;;)
  1524.     {
  1525.       if (fgets (line, sizeof (line)-1, ifp) == NULL) return (-1);
  1526.       if (line[0] != '#') break;
  1527.     }
  1528.   if (sscanf (line, "%d%d", width, height) != 2) return (-1);
  1529.   *maxval = 255;
  1530.  
  1531.   if (pnmtype != 4)  /* Read maxval */
  1532.     {
  1533.       for (;;)
  1534.     {
  1535.       if (fgets (line, sizeof (line)-1, ifp) == NULL) return (-1);
  1536.       if (line[0] != '#') break;
  1537.     }
  1538.       if (sscanf (line, "%d", maxval) != 1) return (-1);
  1539.     }
  1540.   return (pnmtype);
  1541. }
  1542.  
  1543.  
  1544. /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
  1545. static gint32
  1546. create_new_image (gchar       *filename,
  1547.                   guint        pagenum,
  1548.                   guint        width,
  1549.                   guint        height,
  1550.                   GimpImageBaseType   type,
  1551.                   gint32      *layer_ID,
  1552.                   GimpDrawable  **drawable,
  1553.                   GimpPixelRgn   *pixel_rgn)
  1554. {
  1555.   gint32 image_ID;
  1556.   GimpImageType gdtype;
  1557.   char *tmp;
  1558.  
  1559.   if (type == GIMP_GRAY) gdtype = GIMP_GRAY_IMAGE;
  1560.   else if (type == GIMP_INDEXED) gdtype = GIMP_INDEXED_IMAGE;
  1561.   else gdtype = GIMP_RGB_IMAGE;
  1562.  
  1563.   image_ID = gimp_image_new (width, height, type);
  1564.   tmp = g_strdup_printf ("%s-pg%ld", filename, (long)pagenum);
  1565.   gimp_image_set_filename (image_ID, tmp);
  1566.   g_free (tmp);
  1567.  
  1568.   *layer_ID = gimp_layer_new (image_ID, "Background", width, height,
  1569.                   gdtype, 100, GIMP_NORMAL_MODE);
  1570.   gimp_image_add_layer (image_ID, *layer_ID, 0);
  1571.  
  1572.   *drawable = gimp_drawable_get (*layer_ID);
  1573.   gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width,
  1574.                (*drawable)->height, TRUE, FALSE);
  1575.  
  1576.   return (image_ID);
  1577. }
  1578.  
  1579.  
  1580. /* Skip PNM image generated from PostScript file. */
  1581. /* Returns 0 on success, -1 on failure. */
  1582. static gint32
  1583. skip_ps (FILE *ifp)
  1584. {
  1585.   register int k, c;
  1586.   int i, pnmtype, width, height, maxval, bpl;
  1587.  
  1588.   pnmtype = read_pnmraw_type (ifp, &width, &height, &maxval);
  1589.  
  1590.   if (pnmtype == 4)    /* Portable bitmap */
  1591.     bpl = (width + 7)/8;
  1592.   else if (pnmtype == 5)
  1593.     bpl = width;
  1594.   else if (pnmtype == 6)
  1595.     bpl = width*3;
  1596.   else
  1597.     return (-1);
  1598.  
  1599.   for (i = 0; i < height; i++)
  1600.     {
  1601.       k = bpl;  c = EOF;
  1602.       while (k-- > 0) c = getc (ifp);
  1603.       if (c == EOF) return (-1);
  1604.  
  1605.       if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0))
  1606.     gimp_progress_update ((double)(i+1) / (double)height);
  1607.     }
  1608.  
  1609.   return (0);
  1610. }
  1611.  
  1612.  
  1613. /* Load PNM image generated from PostScript file */
  1614. static gint32
  1615. load_ps (gchar *filename,
  1616.          guint  pagenum,
  1617.          FILE  *ifp,
  1618.          gint   llx,
  1619.          gint   lly,
  1620.          gint   urx,
  1621.          gint   ury)
  1622. {
  1623.   register guchar *dest;
  1624.   guchar *data, *bitline = NULL, *byteline = NULL, *byteptr, *temp;
  1625.   guchar bit2byte[256*8];
  1626.   int width, height, tile_height, scan_lines, total_scan_lines;
  1627.   int image_width, image_height;
  1628.   int skip_left, skip_bottom;
  1629.   int i, j, pnmtype, maxval, bpp, nread;
  1630.   GimpImageBaseType imagetype;
  1631.   gint32 layer_ID, image_ID;
  1632.   GimpPixelRgn pixel_rgn;
  1633.   GimpDrawable *drawable;
  1634.   int err = 0, e;
  1635.  
  1636.   pnmtype = read_pnmraw_type (ifp, &width, &height, &maxval);
  1637.  
  1638.   if ((width == urx+1) && (height == ury+1))  /* gs respected BoundingBox ? */
  1639.     {
  1640.       skip_left = llx;    skip_bottom = lly;
  1641.       image_width = width - skip_left;
  1642.       image_height = height - skip_bottom;
  1643.     }
  1644.   else
  1645.     {
  1646.       skip_left = skip_bottom = 0;
  1647.       image_width = width;
  1648.       image_height = height;
  1649.     }
  1650.   if (pnmtype == 4)   /* Portable Bitmap */
  1651.     {
  1652.       imagetype = GIMP_INDEXED;
  1653.       nread = (width+7)/8;
  1654.       bpp = 1;
  1655.       bitline = (guchar *)g_malloc (nread);
  1656.       byteline = (guchar *)g_malloc (nread*8);
  1657.  
  1658.       /* Get an array for mapping 8 bits in a byte to 8 bytes */
  1659.       temp = bit2byte;
  1660.       for (j = 0; j < 256; j++)
  1661.     for (i = 7; i >= 0; i--)
  1662.       *(temp++) = ((j & (1 << i)) != 0);
  1663.     }
  1664.   else if (pnmtype == 5)  /* Portable Greymap */
  1665.     {
  1666.       imagetype = GIMP_GRAY;
  1667.       nread = width;
  1668.       bpp = 1;
  1669.       byteline = (unsigned char *)g_malloc (nread);
  1670.     }
  1671.   else if (pnmtype == 6)  /* Portable Pixmap */
  1672.     {
  1673.       imagetype = GIMP_RGB;
  1674.       nread = width * 3;
  1675.       bpp = 3;
  1676.       byteline = (guchar *)g_malloc (nread);
  1677.     }
  1678.   else return (-1);
  1679.  
  1680.   image_ID = create_new_image (filename, pagenum,
  1681.                    image_width, image_height, imagetype,
  1682.                    &layer_ID, &drawable, &pixel_rgn);
  1683.  
  1684.   tile_height = gimp_tile_height ();
  1685.   data = g_malloc (tile_height * image_width * bpp);
  1686.  
  1687.   dest = data;
  1688.   total_scan_lines = scan_lines = 0;
  1689.  
  1690.   if (pnmtype == 4)   /* Read bitimage ? Must be mapped to indexed */
  1691.     {static unsigned char BWColorMap[2*3] = { 255, 255, 255, 0, 0, 0 };
  1692.  
  1693.     gimp_image_set_cmap (image_ID, BWColorMap, 2);
  1694.  
  1695.     for (i = 0; i < height; i++)
  1696.       {
  1697.     e = (fread (bitline, 1, nread, ifp) != nread);
  1698.     if (total_scan_lines >= image_height) continue;
  1699.     err |= e;
  1700.     if (err) break;
  1701.  
  1702.     j = width;      /* Map 1 byte of bitimage to 8 bytes of indexed image */
  1703.     temp = bitline;
  1704.     byteptr = byteline;
  1705.     while (j >= 8)
  1706.       {
  1707.         memcpy (byteptr, bit2byte + *(temp++)*8, 8);
  1708.         byteptr += 8;
  1709.         j -= 8;
  1710.       }
  1711.     if (j > 0)
  1712.       memcpy (byteptr, bit2byte + *temp*8, j);
  1713.  
  1714.     memcpy (dest, byteline+skip_left, image_width);
  1715.     dest += image_width;
  1716.     scan_lines++;
  1717.     total_scan_lines++;
  1718.  
  1719.     if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0))
  1720.       gimp_progress_update ((double)(i+1) / (double)image_height);
  1721.  
  1722.     if ((scan_lines == tile_height) || ((i+1) == image_height))
  1723.       {
  1724.         gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1,
  1725.                      image_width, scan_lines);
  1726.         scan_lines = 0;
  1727.         dest = data;
  1728.       }
  1729.     if (err) break;
  1730.       }
  1731.     }
  1732.   else   /* Read gray/rgb-image */
  1733.     {
  1734.       for (i = 0; i < height; i++)
  1735.     {
  1736.       e = (fread (byteline, bpp, width, ifp) != width);
  1737.       if (total_scan_lines >= image_height) continue;
  1738.       err |= e;
  1739.       if (err) break;
  1740.  
  1741.       memcpy (dest, byteline+skip_left*bpp, image_width*bpp);
  1742.       dest += image_width*bpp;
  1743.       scan_lines++;
  1744.       total_scan_lines++;
  1745.  
  1746.       if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0))
  1747.         gimp_progress_update ((double)(i+1) / (double)image_height);
  1748.  
  1749.       if ((scan_lines == tile_height) || ((i+1) == image_height))
  1750.         {
  1751.           gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1,
  1752.                        image_width, scan_lines);
  1753.           scan_lines = 0;
  1754.           dest = data;
  1755.         }
  1756.       if (err) break;
  1757.     }
  1758.     }
  1759.  
  1760.   g_free (data);
  1761.   if (byteline) g_free (byteline);
  1762.   if (bitline) g_free (bitline);
  1763.  
  1764.   if (err)
  1765.     g_message ("EOF encountered on reading");
  1766.  
  1767.   gimp_drawable_flush (drawable);
  1768.  
  1769.   return (err ? -1 : image_ID);
  1770. }
  1771.  
  1772.  
  1773. /* Write out the PostScript file header */
  1774. static void save_ps_header (FILE  *ofp,
  1775.                             gchar *filename)
  1776. {
  1777.   time_t cutime = time (NULL);
  1778.  
  1779.   fprintf (ofp, "%%!PS-Adobe-3.0%s\n", psvals.eps ? " EPSF-3.0" : "");
  1780.   fprintf (ofp, "%%%%Creator: GIMP PostScript file plugin V %4.2f \
  1781. by Peter Kirchgessner\n", VERSIO);
  1782.   fprintf (ofp, "%%%%Title: %s\n", filename);
  1783.   fprintf (ofp, "%%%%CreationDate: %s", ctime (&cutime));
  1784.   fprintf (ofp, "%%%%DocumentData: Clean7Bit\n");
  1785.   if (psvals.eps || (psvals.level > 1)) fprintf (ofp,"%%%%LanguageLevel: 2\n");
  1786.   fprintf (ofp, "%%%%Pages: 1\n");
  1787. }
  1788.  
  1789.  
  1790. /* Write out transformation for image */
  1791. static void
  1792. save_ps_setup (FILE   *ofp,
  1793.                gint32  drawable_ID,
  1794.                gint    width,
  1795.                gint    height,
  1796.                gint    bpp)
  1797. {
  1798.   double x_offset, y_offset, x_size, y_size;
  1799.   double urx, ury;
  1800.   double x_scale, y_scale;
  1801.   double width_inch, height_inch;
  1802.   double f1, f2, dx, dy;
  1803.   int xtrans, ytrans;
  1804.   int i_urx, i_ury;
  1805.  
  1806.   /* initialize */
  1807.  
  1808.   dx = 0.0;
  1809.   dy = 0.0;
  1810.  
  1811.   x_offset = psvals.x_offset;
  1812.   y_offset = psvals.y_offset;
  1813.   width_inch = fabs (psvals.width);
  1814.   height_inch = fabs (psvals.height);
  1815.  
  1816.   if (psvals.unit_mm)
  1817.     {
  1818.       x_offset /= 25.4; y_offset /= 25.4;
  1819.       width_inch /= 25.4; height_inch /= 25.4;
  1820.     }
  1821.   if (psvals.keep_ratio)   /* Proportions to keep ? */
  1822.     {                        /* Fit the image into the allowed size */
  1823.       f1 = width_inch / width;
  1824.       f2 = height_inch / height;
  1825.       if (f1 < f2)
  1826.     height_inch = width_inch * (double)(height)/(double)(width);
  1827.       else
  1828.     width_inch = fabs (height_inch) * (double)(width)/(double)(height);
  1829.     }
  1830.   if ((psvals.rotate == 0) || (psvals.rotate == 180))
  1831.     {
  1832.       x_size = width_inch; y_size = height_inch;
  1833.     }
  1834.   else
  1835.   {
  1836.     y_size = width_inch; x_size = height_inch;
  1837.   }
  1838.  
  1839.   /* Round up upper right corner only for non-integer values */
  1840.   urx = (x_offset+x_size)*72.0;
  1841.   ury = (y_offset+y_size)*72.0;
  1842.   i_urx = (int)urx;
  1843.   i_ury = (int)ury;
  1844.   if (urx != (double)i_urx) i_urx++;  /* Check for non-integer value */
  1845.   if (ury != (double)i_ury) i_ury++;
  1846.  
  1847.   fprintf (ofp, "%%%%BoundingBox: %d %d %d %d\n",(int)(x_offset*72.0),
  1848.            (int)(y_offset*72.0), i_urx, i_ury);
  1849.   fprintf (ofp, "%%%%EndComments\n");
  1850.  
  1851.   if (psvals.preview && (psvals.preview_size > 0))
  1852.     {
  1853.       save_ps_preview (ofp, drawable_ID);
  1854.     }
  1855.  
  1856.   fprintf (ofp, "%%%%BeginProlog\n");
  1857.   fprintf (ofp, "%% Use own dictionary to avoid conflicts\n");
  1858.   fprintf (ofp, "10 dict begin\n");
  1859.   fprintf (ofp, "%%%%EndProlog\n");
  1860.   fprintf (ofp, "%%%%Page: 1 1\n");
  1861.   fprintf (ofp, "%% Translate for offset\n");
  1862.   fprintf (ofp, "%f %f translate\n", x_offset*72.0, y_offset*72.0);
  1863.  
  1864.   /* Calculate translation to startpoint of first scanline */
  1865.   switch (psvals.rotate)
  1866.     {
  1867.     case   0: dx = 0.0; dy = y_size*72.0;
  1868.       break;
  1869.     case  90: dx = dy = 0.0;
  1870.       x_scale = 72.0 * width_inch;
  1871.       y_scale = -72.0 * height_inch;
  1872.       break;
  1873.     case 180: dx = x_size*72.0; dy = 0.0;
  1874.       break;
  1875.     case 270: dx = x_size*72.0; dy = y_size*72.0;
  1876.       break;
  1877.     }
  1878.   if ((dx != 0.0) || (dy != 0.0))
  1879.     fprintf (ofp, "%% Translate to begin of first scanline\n%f %f translate\n",
  1880.              dx, dy);
  1881.   if (psvals.rotate)
  1882.     fprintf (ofp, "%d rotate\n", (int)psvals.rotate);
  1883.   fprintf (ofp, "%f %f scale\n", 72.0*width_inch, -72.0*height_inch);
  1884.  
  1885.   /* Write the PostScript procedures to read the image */
  1886.   if (psvals.level <= 1)
  1887.   {
  1888.     fprintf (ofp, "%% Variable to keep one line of raster data\n");
  1889.     if (bpp == 1)
  1890.       fprintf (ofp, "/scanline %d string def\n", (width+7)/8);
  1891.     else
  1892.       fprintf (ofp, "/scanline %d %d mul string def\n", width, bpp/8);
  1893.   }
  1894.   fprintf (ofp, "%% Image geometry\n%d %d %d\n", width, height,
  1895.            (bpp == 1) ? 1 : 8);
  1896.   fprintf (ofp, "%% Transformation matrix\n");
  1897.   xtrans = ytrans = 0;
  1898.   if (psvals.width < 0.0) { width = -width; xtrans = -width; }
  1899.   if (psvals.height < 0.0) { height = -height; ytrans = -height; }
  1900.   fprintf (ofp, "[ %d 0 0 %d %d %d ]\n", width, height, xtrans, ytrans);
  1901. }
  1902.  
  1903.  
  1904. static void
  1905. save_ps_trailer (FILE *ofp)
  1906. {
  1907.   fprintf (ofp, "%%%%Trailer\n");
  1908.   fprintf (ofp, "end\n%%%%EOF\n");
  1909. }
  1910.  
  1911. /* Do a Floyd-Steinberg dithering on a greyscale scanline. */
  1912. /* linecount must keep the counter for the actual scanline (0, 1, 2, ...). */
  1913. /* If linecount is less than zero, all used memory is freed. */
  1914.  
  1915. static void
  1916. dither_grey (guchar *grey,
  1917.              guchar *bw,
  1918.              gint    npix,
  1919.              gint    linecount)
  1920. {
  1921.   register guchar *greyptr, *bwptr, mask;
  1922.   register int *fse;
  1923.   int x, greyval, fse_inline;
  1924.   static int *fs_error = NULL;
  1925.   static int do_init_arrays = 1;
  1926.   static int limit_array[1278];
  1927.   static int east_error[256],seast_error[256],south_error[256],swest_error[256];
  1928.   int *limit = &(limit_array[512]);
  1929.  
  1930.   if (linecount <= 0)
  1931.     {
  1932.       if (fs_error) g_free (fs_error-1);
  1933.       if (linecount < 0) return;
  1934.       fs_error = (int *)g_malloc ((npix+2)*sizeof (int));
  1935.       memset ((char *)fs_error, 0, (npix+2)*sizeof (int));
  1936.       fs_error++;
  1937.  
  1938.       /* Initialize some arrays that speed up dithering */
  1939.       if (do_init_arrays)
  1940.     {
  1941.       do_init_arrays = 0;
  1942.       for (x = -511; x <= 766; x++)
  1943.         limit[x] = (x < 0) ? 0 : ((x > 255) ? 255 : x);
  1944.       for (greyval = 0; greyval < 256; greyval++)
  1945.         {
  1946.           east_error[greyval] = (greyval < 128) ? ((greyval * 79) >> 8)
  1947.         : (((greyval-255)*79) >> 8);
  1948.           seast_error[greyval] = (greyval < 128) ? ((greyval * 34) >> 8)
  1949.         : (((greyval-255)*34) >> 8);
  1950.           south_error[greyval] = (greyval < 128) ? ((greyval * 56) >> 8)
  1951.         : (((greyval-255)*56) >> 8);
  1952.           swest_error[greyval] = (greyval < 128) ? ((greyval * 12) >> 8)
  1953.         : (((greyval-255)*12) >> 8);
  1954.         }
  1955.     }
  1956.     }
  1957.   if (fs_error == NULL) return;
  1958.  
  1959.   memset (bw, 0, (npix+7)/8); /* Initialize with white */
  1960.  
  1961.   greyptr = grey;
  1962.   bwptr = bw;
  1963.   mask = 0x80;
  1964.   fse_inline = fs_error[0];
  1965.   for (x = 0, fse = fs_error; x < npix; x++, fse++)
  1966.     {
  1967.       greyval = limit[*(greyptr++) + fse_inline];  /* 0 <= greyval <= 255 */
  1968.       if (greyval < 128) *bwptr |= mask;  /* Set a black pixel */
  1969.  
  1970.       /* Error distribution */
  1971.       fse_inline = east_error[greyval] + fse[1];
  1972.       fse[1] = seast_error[greyval];
  1973.       fse[0] += south_error[greyval];
  1974.       fse[-1] += swest_error[greyval];
  1975.  
  1976.       mask >>= 1;   /* Get mask for next b/w-pixel */
  1977.       if (!mask)
  1978.     {
  1979.       mask = 0x80;
  1980.       bwptr++;
  1981.     }
  1982.     }
  1983. }
  1984.  
  1985. /* Write a device independant screen preview */
  1986. static void
  1987. save_ps_preview (FILE   *ofp,
  1988.                  gint32  drawable_ID)
  1989. {
  1990.   register guchar *bwptr, *greyptr;
  1991.   GimpImageType drawable_type;
  1992.   GimpDrawable *drawable;
  1993.   GimpPixelRgn src_rgn;
  1994.   int width, height, x, y, nbsl, out_count;
  1995.   int nchar_pl = 72, src_y;
  1996.   double f1, f2;
  1997.   guchar *grey, *bw, *src_row, *src_ptr;
  1998.   guchar *cmap;
  1999.   gint ncols, cind;
  2000.  
  2001.   if (psvals.preview_size <= 0) return;
  2002.  
  2003.   drawable = gimp_drawable_get (drawable_ID);
  2004.   drawable_type = gimp_drawable_type (drawable_ID);
  2005.  
  2006.   /* Calculate size of preview */
  2007.   if (   (drawable->width <= psvals.preview_size)
  2008.      && (drawable->height <= psvals.preview_size))
  2009.     {
  2010.       width = drawable->width;
  2011.       height = drawable->height;
  2012.     }
  2013.   else
  2014.     {
  2015.       f1 = (double)psvals.preview_size / (double)drawable->width;
  2016.       f2 = (double)psvals.preview_size / (double)drawable->height;
  2017.       if (f1 < f2)
  2018.     {
  2019.       width = psvals.preview_size;
  2020.       height = drawable->height * f1;
  2021.       if (height <= 0) height = 1;
  2022.     }
  2023.       else
  2024.     {
  2025.       height = psvals.preview_size;
  2026.       width = drawable->width * f1;
  2027.       if (width <= 0) width = 1;
  2028.     }
  2029.     }
  2030.  
  2031.   nbsl = (width+7)/8;  /* Number of bytes per scanline in bitmap */
  2032.  
  2033.   grey = (guchar *)g_malloc (width);
  2034.   bw = (guchar *)g_malloc (nbsl);
  2035.   src_row = (guchar *)g_malloc (drawable->width * drawable->bpp);
  2036.  
  2037.   fprintf (ofp, "%%%%BeginPreview: %d %d 1 %d\n", width, height,
  2038.        ((nbsl*2+nchar_pl-1)/nchar_pl)*height);
  2039.  
  2040.   gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width,
  2041.                drawable->height, FALSE, FALSE);
  2042.  
  2043.   cmap = NULL;     /* Check if we need a colour table */
  2044.   if (gimp_drawable_type (drawable_ID) == GIMP_INDEXED_IMAGE)
  2045.     cmap = (guchar *)
  2046.       gimp_image_get_cmap (gimp_drawable_image_id (drawable_ID), &ncols);
  2047.  
  2048.   for (y = 0; y < height; y++)
  2049.     {
  2050.       /* Get a scanline from the input image and scale it to the desired width */
  2051.       src_y = (y * drawable->height) / height;
  2052.       gimp_pixel_rgn_get_row (&src_rgn, src_row, 0, src_y, drawable->width);
  2053.  
  2054.       greyptr = grey;
  2055.       if (drawable->bpp == 3)   /* RGB-image */
  2056.     {
  2057.       for (x = 0; x < width; x++)
  2058.         {                       /* Convert to grey */
  2059.           src_ptr = src_row + ((x * drawable->width) / width) * 3;
  2060.           *(greyptr++) = (3*src_ptr[0] + 6*src_ptr[1] + src_ptr[2]) / 10;
  2061.         }
  2062.     }
  2063.       else if (cmap)    /* Indexed image */
  2064.     {
  2065.       for (x = 0; x < width; x++)
  2066.         {
  2067.           src_ptr = src_row + ((x * drawable->width) / width);
  2068.           cind = *src_ptr;   /* Get colour index and convert to grey */
  2069.           src_ptr = (cind >= ncols) ? cmap : (cmap + 3*cind);
  2070.           *(greyptr++) = (3*src_ptr[0] + 6*src_ptr[1] + src_ptr[2]) / 10;
  2071.         }
  2072.     }
  2073.       else             /* Grey image */
  2074.     {
  2075.       for (x = 0; x < width; x++)
  2076.         *(greyptr++) = *(src_row + ((x * drawable->width) / width));
  2077.     }
  2078.  
  2079.       /* Now we have a greyscale line for the desired width. */
  2080.       /* Dither it to b/w */
  2081.       dither_grey (grey, bw, width, y);
  2082.  
  2083.       /* Write out the b/w line */
  2084.       out_count = 0;
  2085.       bwptr = bw;
  2086.       for (x = 0; x < nbsl; x++)
  2087.     {
  2088.       if (out_count == 0) fprintf (ofp, "%% ");
  2089.       fprintf (ofp, "%02x", *(bwptr++));
  2090.       out_count += 2;
  2091.       if (out_count >= nchar_pl)
  2092.         {
  2093.           fprintf (ofp, "\n");
  2094.           out_count = 0;
  2095.         }
  2096.     }
  2097.       if (out_count != 0)
  2098.     fprintf (ofp, "\n");
  2099.  
  2100.       if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((y % 20) == 0))
  2101.     gimp_progress_update ((double)(y) / (double)height);
  2102.     }
  2103.  
  2104.   fprintf (ofp, "%%%%EndPreview\n");
  2105.  
  2106.   dither_grey (grey, bw, width, -1);
  2107.   g_free (src_row);
  2108.   g_free (bw);
  2109.   g_free (grey);
  2110.  
  2111.   gimp_drawable_detach (drawable);
  2112. }
  2113.  
  2114. static gint
  2115. save_gray  (FILE   *ofp,
  2116.             gint32  image_ID,
  2117.             gint32  drawable_ID)
  2118. {
  2119.   int height, width, i, j;
  2120.   int tile_height;
  2121.   unsigned char *data, *src;
  2122.   unsigned char *packb = NULL;
  2123.   GimpPixelRgn pixel_rgn;
  2124.   GimpDrawable *drawable;
  2125.   GimpImageType drawable_type;
  2126.   static char *hex = "0123456789abcdef";
  2127.   int level2 = (psvals.level > 1);
  2128.  
  2129.   drawable = gimp_drawable_get (drawable_ID);
  2130.   drawable_type = gimp_drawable_type (drawable_ID);
  2131.   width = drawable->width;
  2132.   height = drawable->height;
  2133.   tile_height = gimp_tile_height ();
  2134.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
  2135.  
  2136.   /* allocate a buffer for retrieving information from the pixel region  */
  2137.   src = data = (guchar *)g_malloc (tile_height * width * drawable->bpp);
  2138.  
  2139.   /* Set up transformation in PostScript */
  2140.   save_ps_setup (ofp, drawable_ID, width, height, 1*8);
  2141.  
  2142.   /* Write read image procedure */
  2143.   if (!level2)
  2144.   {
  2145.     fprintf (ofp, "{ currentfile scanline readhexstring pop }\n");
  2146.   }
  2147.   else
  2148.   {
  2149.     fprintf (ofp,"currentfile /ASCII85Decode filter /RunLengthDecode filter\n");
  2150.     ascii85_init ();
  2151.     /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
  2152.     packb = (guchar *)g_malloc ((width * 105)/100+2);
  2153.   }
  2154.   ps_begin_data (ofp);
  2155.   fprintf (ofp, "image\n");
  2156.  
  2157. #define GET_GRAY_TILE(begin) \
  2158.   {int scan_lines; \
  2159.     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
  2160.     gimp_pixel_rgn_get_rect (&pixel_rgn, begin, 0, i, width, scan_lines); \
  2161.     src = begin; }
  2162.  
  2163.   for (i = 0; i < height; i++)
  2164.     {
  2165.       if ((i % tile_height) == 0) GET_GRAY_TILE (data); /* Get more data */
  2166.       if (!level2)
  2167.     {
  2168.       for (j = 0; j < width; j++)
  2169.         {
  2170.           putc (hex[(*src) >> 4], ofp);
  2171.           putc (hex[(*(src++)) & 0x0f], ofp);
  2172.           if (((j+1) % 39) == 0) putc ('\n', ofp);
  2173.         }
  2174.       putc ('\n', ofp);
  2175.     }
  2176.       else
  2177.     {int nout;
  2178.  
  2179.           compress_packbits (width, src, &nout, packb);
  2180.           ascii85_nout (nout, packb, ofp);
  2181.           src += width;
  2182.     }
  2183.       if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0))
  2184.     gimp_progress_update ((double) i / (double) height);
  2185.     }
  2186.   if (level2)
  2187.   {
  2188.     ascii85_out (128, ofp); /* Write EOD of RunLengthDecode filter */
  2189.     ascii85_done (ofp);
  2190.   }
  2191.   ps_end_data (ofp);
  2192.   fprintf (ofp, "showpage\n");
  2193.   g_free (data);
  2194.   if (packb) g_free (packb);
  2195.  
  2196.   gimp_drawable_detach (drawable);
  2197.  
  2198.   if (ferror (ofp))
  2199.     {
  2200.       g_message (_("write error occured"));
  2201.       return (FALSE);
  2202.     }
  2203.   return (TRUE);
  2204. #undef GET_GRAY_TILE
  2205. }
  2206.  
  2207.  
  2208. static gint
  2209. save_bw (FILE   *ofp,
  2210.          gint32  image_ID,
  2211.          gint32  drawable_ID)
  2212. {
  2213.   int height, width, i, j;
  2214.   int ncols, nbsl, nwrite;
  2215.   int tile_height;
  2216.   guchar *cmap, *ct;
  2217.   guchar *data, *src;
  2218.   guchar *packb = NULL;
  2219.   guchar *scanline, *dst, mask;
  2220.   guchar *hex_scanline;
  2221.   GimpPixelRgn pixel_rgn;
  2222.   GimpDrawable *drawable;
  2223.   GimpImageType drawable_type;
  2224.   static char *hex = "0123456789abcdef";
  2225.   int level2 = (psvals.level > 1);
  2226.  
  2227.   cmap = gimp_image_get_cmap (image_ID, &ncols);
  2228.  
  2229.   drawable = gimp_drawable_get (drawable_ID);
  2230.   drawable_type = gimp_drawable_type (drawable_ID);
  2231.   width = drawable->width;
  2232.   height = drawable->height;
  2233.   tile_height = gimp_tile_height ();
  2234.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
  2235.  
  2236.   /* allocate a buffer for retrieving information from the pixel region  */
  2237.   src = data = (guchar *)g_malloc (tile_height * width * drawable->bpp);
  2238.   nbsl = (width+7)/8;
  2239.   scanline = (char *)g_malloc (nbsl + 1);
  2240.   hex_scanline = (char *)g_malloc ((nbsl + 1)*2);
  2241.  
  2242.   /* Set up transformation in PostScript */
  2243.   save_ps_setup (ofp, drawable_ID, width, height, 1);
  2244.  
  2245.   /* Write read image procedure */
  2246.   if (!level2)
  2247.   {
  2248.     fprintf (ofp, "{ currentfile scanline readhexstring pop }\n");
  2249.   }
  2250.   else
  2251.   {
  2252.     fprintf (ofp,"currentfile /ASCII85Decode filter /RunLengthDecode filter\n");
  2253.     ascii85_init ();
  2254.     /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
  2255.     packb = (guchar *)g_malloc (((nbsl+1) * 105)/100+2);
  2256.   }
  2257.   ps_begin_data (ofp);
  2258.   fprintf (ofp, "image\n");
  2259.  
  2260. #define GET_BW_TILE(begin) \
  2261.   {int scan_lines; \
  2262.     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
  2263.     gimp_pixel_rgn_get_rect (&pixel_rgn, begin, 0, i, width, scan_lines); \
  2264.     src = begin; }
  2265.  
  2266.   for (i = 0; i < height; i++)
  2267.     {
  2268.       if ((i % tile_height) == 0) GET_BW_TILE (data); /* Get more data */
  2269.       dst = scanline;
  2270.       memset (dst, 0, nbsl);
  2271.       mask = 0x80;
  2272.       /* Build a bitmap for a scanline */
  2273.       for (j = 0; j < width; j++)
  2274.     {
  2275.       ct = cmap + *(src++)*3;
  2276.       if (ct[0] || ct[1] || ct[2])
  2277.         *dst |= mask;
  2278.       if (mask == 0x01) { mask = 0x80; dst++; } else mask >>= 1;
  2279.     }
  2280.       if (!level2)
  2281.     {
  2282.       /* Convert to hexstring */
  2283.       for (j = 0; j < nbsl; j++)
  2284.         {
  2285.           hex_scanline[j*2] = (unsigned char)hex[scanline[j] >> 4];
  2286.           hex_scanline[j*2+1] = (unsigned char)hex[scanline[j] & 0x0f];
  2287.         }
  2288.       /* Write out hexstring */
  2289.       j = nbsl * 2;
  2290.       dst = hex_scanline;
  2291.       while (j > 0)
  2292.         {
  2293.           nwrite = (j > 78) ? 78 : j;
  2294.           fwrite (dst, nwrite, 1, ofp);
  2295.           putc ('\n', ofp);
  2296.           j -= nwrite;
  2297.           dst += nwrite;
  2298.         }
  2299.     }
  2300.       else
  2301.     {int nout;
  2302.  
  2303.           compress_packbits (nbsl, scanline, &nout, packb);
  2304.           ascii85_nout (nout, packb, ofp);
  2305.     }
  2306.       if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0))
  2307.     gimp_progress_update ((double) i / (double) height);
  2308.     }
  2309.   if (level2)
  2310.   {
  2311.     ascii85_out (128, ofp); /* Write EOD of RunLengthDecode filter */
  2312.     ascii85_done (ofp);
  2313.   }
  2314.   ps_end_data (ofp);
  2315.   fprintf (ofp, "showpage\n");
  2316.  
  2317.   g_free (hex_scanline);
  2318.   g_free (scanline);
  2319.   g_free (data);
  2320.   if (packb != NULL) g_free (packb);
  2321.  
  2322.   gimp_drawable_detach (drawable);
  2323.  
  2324.   if (ferror (ofp))
  2325.     {
  2326.       g_message (_("write error occured"));
  2327.       return (FALSE);
  2328.     }
  2329.   return (TRUE);
  2330. #undef GET_BW_TILE
  2331. }
  2332.  
  2333.  
  2334. static gint
  2335. save_index (FILE   *ofp,
  2336.             gint32  image_ID,
  2337.             gint32  drawable_ID)
  2338. {
  2339.   int height, width, i, j;
  2340.   int ncols, bw;
  2341.   int tile_height;
  2342.   guchar *cmap, *cmap_start;
  2343.   guchar *data, *src;
  2344.   guchar *packb = NULL, *plane = NULL;
  2345.   char coltab[256*6], *ct;
  2346.   GimpPixelRgn pixel_rgn;
  2347.   GimpDrawable *drawable;
  2348.   GimpImageType drawable_type;
  2349.   static char *hex = "0123456789abcdef";
  2350.   static char *background = "000000";
  2351.   int level2 = (psvals.level > 1);
  2352.  
  2353.   cmap = cmap_start = gimp_image_get_cmap (image_ID, &ncols);
  2354.  
  2355.   ct = coltab;
  2356.   bw = 1;
  2357.   for (j = 0; j < 256; j++)
  2358.     {
  2359.       if (j >= ncols)
  2360.     {
  2361.       memcpy (ct, background, 6);
  2362.       ct += 6;
  2363.     }
  2364.       else
  2365.     {
  2366.       bw &=    ((cmap[0] == 0) && (cmap[1] == 0) && (cmap[2] == 0))
  2367.             || ((cmap[0] == 255) && (cmap[1] == 255) && (cmap[2] == 255));
  2368.       *(ct++) = (guchar)hex[(*cmap) >> 4];
  2369.       *(ct++) = (guchar)hex[(*(cmap++)) & 0x0f];
  2370.       *(ct++) = (guchar)hex[(*cmap) >> 4];
  2371.       *(ct++) = (guchar)hex[(*(cmap++)) & 0x0f];
  2372.       *(ct++) = (guchar)hex[(*cmap) >> 4];
  2373.       *(ct++) = (guchar)hex[(*(cmap++)) & 0x0f];
  2374.     }
  2375.     }
  2376.   if (bw) return (save_bw (ofp, image_ID, drawable_ID));
  2377.  
  2378.   drawable = gimp_drawable_get (drawable_ID);
  2379.   drawable_type = gimp_drawable_type (drawable_ID);
  2380.   width = drawable->width;
  2381.   height = drawable->height;
  2382.   tile_height = gimp_tile_height ();
  2383.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
  2384.  
  2385.   /* allocate a buffer for retrieving information from the pixel region  */
  2386.   src = data = (guchar *)g_malloc (tile_height * width * drawable->bpp);
  2387.  
  2388.   /* Set up transformation in PostScript */
  2389.   save_ps_setup (ofp, drawable_ID, width, height, 3*8);
  2390.  
  2391.   /* Write read image procedure */
  2392.   if (!level2)
  2393.   {
  2394.     fprintf (ofp, "{ currentfile scanline readhexstring pop } false 3\n");
  2395.   }
  2396.   else
  2397.   {
  2398.     fprintf (ofp, "%% Strings to hold RGB-samples per scanline\n");
  2399.     fprintf (ofp, "/rstr %d string def\n", width);
  2400.     fprintf (ofp, "/gstr %d string def\n", width);
  2401.     fprintf (ofp, "/bstr %d string def\n", width);
  2402.     fprintf (ofp,
  2403.             "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
  2404.  rstr readstring pop}\n");
  2405.     fprintf (ofp,
  2406.             "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
  2407.  gstr readstring pop}\n");
  2408.     fprintf (ofp,
  2409.             "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
  2410.  bstr readstring pop}\n");
  2411.     fprintf (ofp, "true 3\n");
  2412.  
  2413.     /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
  2414.     packb = (guchar *)g_malloc ((width * 105)/100+2);
  2415.     plane = (guchar *)g_malloc (width);
  2416.   }
  2417.   ps_begin_data (ofp);
  2418.   fprintf (ofp, "colorimage\n");
  2419.  
  2420. #define GET_INDEX_TILE(begin) \
  2421.   {int scan_lines; \
  2422.     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
  2423.     gimp_pixel_rgn_get_rect (&pixel_rgn, begin, 0, i, width, scan_lines); \
  2424.     src = begin; }
  2425.  
  2426.   for (i = 0; i < height; i++)
  2427.     {
  2428.       if ((i % tile_height) == 0) GET_INDEX_TILE (data); /* Get more data */
  2429.       if (!level2)
  2430.     {
  2431.       for (j = 0; j < width; j++)
  2432.         {
  2433.           fwrite (coltab+(*(src++))*6, 6, 1, ofp);
  2434.           if (((j+1) % 13) == 0) putc ('\n', ofp);
  2435.         }
  2436.       putc ('\n', ofp);
  2437.     }
  2438.       else
  2439.         {guchar *plane_ptr, *src_ptr;
  2440.          int rgb, nout;
  2441.  
  2442.           for (rgb = 0; rgb < 3; rgb++)
  2443.           {
  2444.             src_ptr = src;
  2445.             plane_ptr = plane;
  2446.             for (j = 0; j < width; j++)
  2447.               *(plane_ptr++) = cmap_start[3 * *(src_ptr++) + rgb];
  2448.             compress_packbits (width, plane, &nout, packb);
  2449.             ascii85_init ();
  2450.             ascii85_nout (nout, packb, ofp);
  2451.             ascii85_out (128, ofp); /* Write EOD of RunLengthDecode filter */
  2452.             ascii85_done (ofp);
  2453.           }
  2454.           src += width;
  2455.         }
  2456.       if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0))
  2457.     gimp_progress_update ((double) i / (double) height);
  2458.     }
  2459.   ps_end_data (ofp);
  2460.   fprintf (ofp, "showpage\n");
  2461.  
  2462.   g_free (data);
  2463.   if (packb != NULL) g_free (packb);
  2464.   if (plane != NULL) g_free (plane);
  2465.  
  2466.   gimp_drawable_detach (drawable);
  2467.  
  2468.   if (ferror (ofp))
  2469.     {
  2470.       g_message (_("write error occured"));
  2471.       return (FALSE);
  2472.     }
  2473.   return (TRUE);
  2474. #undef GET_INDEX_TILE
  2475. }
  2476.  
  2477.  
  2478. static gint
  2479. save_rgb (FILE   *ofp,
  2480.           gint32  image_ID,
  2481.           gint32  drawable_ID)
  2482. {
  2483.   int height, width, tile_height;
  2484.   int i, j;
  2485.   guchar *data, *src;
  2486.   guchar *packb = NULL, *plane = NULL;
  2487.   GimpPixelRgn pixel_rgn;
  2488.   GimpDrawable *drawable;
  2489.   GimpImageType drawable_type;
  2490.   static char *hex = "0123456789abcdef";
  2491.   int level2 = (psvals.level > 1);
  2492.  
  2493.   drawable = gimp_drawable_get (drawable_ID);
  2494.   drawable_type = gimp_drawable_type (drawable_ID);
  2495.   width = drawable->width;
  2496.   height = drawable->height;
  2497.   tile_height = gimp_tile_height ();
  2498.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
  2499.  
  2500.   /* allocate a buffer for retrieving information from the pixel region  */
  2501.   src = data = (guchar *)g_malloc (tile_height * width * drawable->bpp);
  2502.  
  2503.   /* Set up transformation in PostScript */
  2504.   save_ps_setup (ofp, drawable_ID, width, height, 3*8);
  2505.  
  2506.   /* Write read image procedure */
  2507.   if (!level2)
  2508.   {
  2509.     fprintf (ofp, "{ currentfile scanline readhexstring pop } false 3\n");
  2510.   }
  2511.   else
  2512.   {
  2513.     fprintf (ofp, "%% Strings to hold RGB-samples per scanline\n");
  2514.     fprintf (ofp, "/rstr %d string def\n", width);
  2515.     fprintf (ofp, "/gstr %d string def\n", width);
  2516.     fprintf (ofp, "/bstr %d string def\n", width);
  2517.     fprintf (ofp,
  2518.             "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
  2519.  rstr readstring pop}\n");
  2520.     fprintf (ofp,
  2521.             "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
  2522.  gstr readstring pop}\n");
  2523.     fprintf (ofp,
  2524.             "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
  2525.  bstr readstring pop}\n");
  2526.     fprintf (ofp, "true 3\n");
  2527.  
  2528.     /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
  2529.     packb = (guchar *)g_malloc ((width * 105)/100+2);
  2530.     plane = (guchar *)g_malloc (width);
  2531.   }
  2532.   ps_begin_data (ofp);
  2533.   fprintf (ofp, "colorimage\n");
  2534.  
  2535. #define GET_RGB_TILE(begin) \
  2536.   {int scan_lines; \
  2537.     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
  2538.     gimp_pixel_rgn_get_rect (&pixel_rgn, begin, 0, i, width, scan_lines); \
  2539.     src = begin; }
  2540.  
  2541.   for (i = 0; i < height; i++)
  2542.     {
  2543.       if ((i % tile_height) == 0) GET_RGB_TILE (data); /* Get more data */
  2544.       if (!level2)
  2545.     {
  2546.       for (j = 0; j < width; j++)
  2547.         {
  2548.           putc (hex[(*src) >> 4], ofp);        /* Red */
  2549.           putc (hex[(*(src++)) & 0x0f], ofp);
  2550.           putc (hex[(*src) >> 4], ofp);        /* Green */
  2551.           putc (hex[(*(src++)) & 0x0f], ofp);
  2552.           putc (hex[(*src) >> 4], ofp);        /* Blue */
  2553.           putc (hex[(*(src++)) & 0x0f], ofp);
  2554.           if (((j+1) % 13) == 0) putc ('\n', ofp);
  2555.         }
  2556.       putc ('\n', ofp);
  2557.     }
  2558.       else
  2559.     {guchar *plane_ptr, *src_ptr;
  2560.          int rgb, nout;
  2561.  
  2562.           for (rgb = 0; rgb < 3; rgb++)
  2563.           {
  2564.             src_ptr = src + rgb;
  2565.             plane_ptr = plane;
  2566.             for (j = 0; j < width; j++)
  2567.         {
  2568.               *(plane_ptr++) = *src_ptr;
  2569.               src_ptr += 3;
  2570.             }
  2571.             compress_packbits (width, plane, &nout, packb);
  2572.             ascii85_init ();
  2573.         ascii85_nout (nout, packb, ofp);
  2574.             ascii85_out (128, ofp); /* Write EOD of RunLengthDecode filter */
  2575.             ascii85_done (ofp);
  2576.           }
  2577.           src += 3*width;
  2578.     }
  2579.       if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0))
  2580.     gimp_progress_update ((double) i / (double) height);
  2581.     }
  2582.   ps_end_data (ofp);
  2583.   fprintf (ofp, "showpage\n");
  2584.   g_free (data);
  2585.   if (packb != NULL) g_free (packb);
  2586.   if (plane != NULL) g_free (plane);
  2587.  
  2588.   gimp_drawable_detach (drawable);
  2589.  
  2590.   if (ferror (ofp))
  2591.     {
  2592.       g_message (_("write error occured"));
  2593.       return (FALSE);
  2594.     }
  2595.   return (TRUE);
  2596. #undef GET_RGB_TILE
  2597. }
  2598.  
  2599. /*  Load interface functions  */
  2600.  
  2601. static gint
  2602. load_dialog (void)
  2603. {
  2604.   GtkWidget *dialog;
  2605.   GtkWidget *main_vbox;
  2606.   GtkWidget *hbox;
  2607.   GtkWidget *frame;
  2608.   GtkWidget *vbox;
  2609.   GtkWidget *table;
  2610.   GtkWidget *spinbutton;
  2611.   GtkObject *adj;
  2612.   GtkWidget *pages_entry;
  2613.   GtkWidget *toggle;
  2614.  
  2615.   gimp_ui_init ("ps", FALSE);
  2616.  
  2617.   dialog = gimp_dialog_new (_("Load PostScript"), "ps",
  2618.                 gimp_standard_help_func, "filters/ps.html",
  2619.                 GTK_WIN_POS_MOUSE,
  2620.                 FALSE, TRUE, FALSE,
  2621.  
  2622.                 _("OK"), load_ok_callback,
  2623.                 NULL, NULL, NULL, TRUE, FALSE,
  2624.                 _("Cancel"), gtk_widget_destroy,
  2625.                 NULL, 1, NULL, FALSE, TRUE,
  2626.  
  2627.                 NULL);
  2628.  
  2629.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  2630.                       GTK_SIGNAL_FUNC (gtk_main_quit),
  2631.                       NULL);
  2632.  
  2633.   main_vbox = gtk_vbox_new (FALSE, 6);
  2634.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  2635.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_vbox,
  2636.                       FALSE, FALSE, 0);
  2637.   gtk_widget_show (main_vbox);
  2638.  
  2639.   hbox = gtk_hbox_new (FALSE, 6);
  2640.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  2641.   gtk_widget_show (hbox);
  2642.  
  2643.   /* Rendering */
  2644.   frame = gtk_frame_new (_("Rendering"));
  2645.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  2646.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  2647.  
  2648.   vbox = gtk_vbox_new (FALSE, 4);
  2649.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  2650.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  2651.  
  2652.   /* Resolution/Width/Height/Pages labels */
  2653.   table = gtk_table_new (4, 2, FALSE);
  2654.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  2655.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  2656.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  2657.   gtk_widget_show (table);
  2658.  
  2659.   spinbutton = gimp_spin_button_new (&adj, plvals.resolution,
  2660.                      5, 1440, 1, 10, 0, 1, 0);
  2661.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  2662.                  _("Resolution:"), 1.0, 0.5,
  2663.                  spinbutton, 1, TRUE);
  2664.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2665.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2666.               &plvals.resolution);
  2667.  
  2668.   spinbutton = gimp_spin_button_new (&adj, plvals.width,
  2669.                      1, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 0);
  2670.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  2671.                  _("Width:"), 1.0, 0.5,
  2672.                  spinbutton, 1, TRUE);
  2673.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2674.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2675.               &plvals.width);
  2676.  
  2677.   spinbutton = gimp_spin_button_new (&adj, plvals.height,
  2678.                      1, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 0);
  2679.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
  2680.                  _("Height:"), 1.0, 0.5,
  2681.                  spinbutton, 1, TRUE);
  2682.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2683.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2684.               &plvals.height);
  2685.  
  2686.   pages_entry = gtk_entry_new ();
  2687.   gtk_widget_set_usize (pages_entry, 80, 0);
  2688.   gtk_entry_set_text (GTK_ENTRY (pages_entry), plvals.pages);
  2689.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  2690.                  _("Pages:"), 1.0, 0.5,
  2691.                  pages_entry, 1, TRUE);
  2692.   gtk_signal_connect (GTK_OBJECT (pages_entry), "changed",
  2693.               GTK_SIGNAL_FUNC (load_pages_entry_callback),
  2694.               NULL);
  2695.  
  2696.   toggle = gtk_check_button_new_with_label (_("Try Bounding Box"));
  2697.   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
  2698.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  2699.                       GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  2700.                       &plvals.use_bbox);
  2701.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), plvals.use_bbox);
  2702.   gtk_widget_show (toggle);
  2703.  
  2704.   gtk_widget_show (vbox);
  2705.   gtk_widget_show (frame);
  2706.  
  2707.   /* Colouring */
  2708.   frame = gimp_radio_group_new2 (TRUE, _("Coloring"),
  2709.                  gimp_radio_button_update,
  2710.                  &plvals.pnm_type, GINT_TO_POINTER (plvals.pnm_type),
  2711.  
  2712.                  _("B/W"),       GINT_TO_POINTER (4), NULL,
  2713.                  _("Gray"),      GINT_TO_POINTER (5), NULL,
  2714.                  _("Color"),     GINT_TO_POINTER (6), NULL,
  2715.                  _("Automatic"), GINT_TO_POINTER (7), NULL,
  2716.  
  2717.                  NULL);
  2718.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  2719.   gtk_widget_show (frame);
  2720.  
  2721.   hbox = gtk_hbox_new (TRUE, 6);
  2722.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  2723.   gtk_widget_show (hbox);
  2724.  
  2725.   frame = gimp_radio_group_new2 (TRUE, _("Text Antialiasing"),
  2726.                  gimp_radio_button_update,
  2727.                  &plvals.textalpha, GINT_TO_POINTER (plvals.textalpha),
  2728.  
  2729.                  _("None"),   GINT_TO_POINTER (1), NULL,
  2730.                  _("Weak"),   GINT_TO_POINTER (2), NULL,
  2731.                  _("Strong"), GINT_TO_POINTER (4), NULL,
  2732.  
  2733.                  NULL);
  2734.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
  2735.   gtk_widget_show (frame);
  2736.  
  2737.   frame = gimp_radio_group_new2 (TRUE, _("Graphic Antialiasing"),
  2738.                  gimp_radio_button_update,
  2739.                  &plvals.graphicsalpha,
  2740.                  GINT_TO_POINTER (plvals.graphicsalpha),
  2741.  
  2742.                  _("None"),   GINT_TO_POINTER (1), NULL,
  2743.                  _("Weak"),   GINT_TO_POINTER (2), NULL,
  2744.                  _("Strong"), GINT_TO_POINTER (4), NULL,
  2745.  
  2746.                  NULL);
  2747.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
  2748.   gtk_widget_show (frame);
  2749.  
  2750.   gtk_widget_show (dialog);
  2751.  
  2752.   gtk_main ();
  2753.   gdk_flush ();
  2754.  
  2755.   return plint.run;
  2756. }
  2757.  
  2758.  
  2759. static void
  2760. load_ok_callback (GtkWidget *widget,
  2761.                   gpointer   data)
  2762. {
  2763.   plint.run = TRUE;
  2764.  
  2765.   gtk_widget_destroy (GTK_WIDGET (data));
  2766. }
  2767.  
  2768. static void
  2769. load_pages_entry_callback (GtkWidget *widget,
  2770.                gpointer   data)
  2771. {
  2772.   gint nelem = sizeof (plvals.pages);
  2773.  
  2774.   strncpy (plvals.pages, gtk_entry_get_text (GTK_ENTRY (widget)), nelem);
  2775.   plvals.pages[nelem-1] = '\0';
  2776. }
  2777.  
  2778. /*  Save interface functions  */
  2779.  
  2780. static gint
  2781. save_dialog (void)
  2782. {
  2783.   SaveDialogVals *vals;
  2784.   GtkWidget *dialog;
  2785.   GtkWidget *toggle;
  2786.   GtkWidget *frame, *uframe;
  2787.   GtkWidget *hbox, *vbox;
  2788.   GtkWidget *main_vbox[2];
  2789.   GtkWidget *table;
  2790.   GtkWidget *spinbutton;
  2791.   GtkObject *adj;
  2792.   gint       j;
  2793.  
  2794.   gimp_help_init ();
  2795.  
  2796.   vals = g_new (SaveDialogVals, 1);
  2797.   vals->level = (psvals.level > 1);
  2798.  
  2799.   dialog = gimp_dialog_new (_("Save as PostScript"), "ps",
  2800.                 gimp_standard_help_func, "filters/ps.html",
  2801.                 GTK_WIN_POS_MOUSE,
  2802.                 FALSE, TRUE, FALSE,
  2803.  
  2804.                 _("OK"), save_ok_callback,
  2805.                 NULL, NULL, NULL, TRUE, FALSE,
  2806.                 _("Cancel"), gtk_widget_destroy,
  2807.                 NULL, 1, NULL, FALSE, TRUE,
  2808.  
  2809.                 NULL);
  2810.  
  2811.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  2812.                       GTK_SIGNAL_FUNC (gtk_main_quit),
  2813.                       NULL);
  2814.  
  2815.   /* Main hbox */
  2816.   hbox = gtk_hbox_new (FALSE, 6);
  2817.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
  2818.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
  2819.                       FALSE, FALSE, 0);
  2820.   main_vbox[0] = main_vbox[1] = NULL;
  2821.  
  2822.   for (j = 0; j < sizeof (main_vbox) / sizeof (main_vbox[0]); j++)
  2823.     {
  2824.       main_vbox[j] = gtk_vbox_new (FALSE, 4);
  2825.       gtk_box_pack_start (GTK_BOX (hbox), main_vbox[j], TRUE, TRUE, 0);
  2826.     }
  2827.  
  2828.   /* Image Size */
  2829.   frame = gtk_frame_new (_("Image Size"));
  2830.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  2831.   gtk_box_pack_start (GTK_BOX (main_vbox[0]), frame, TRUE, TRUE, 0);
  2832.  
  2833.   vbox = gtk_vbox_new (FALSE, 4);
  2834.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  2835.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  2836.  
  2837.   /* Width/Height/X-/Y-offset labels */
  2838.   table = gtk_table_new (4, 2, FALSE);
  2839.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  2840.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  2841.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  2842.   gtk_widget_show (table);
  2843.  
  2844.   spinbutton = gimp_spin_button_new (&vals->adjustment[0], psvals.width,
  2845.                      1e-5, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 2);
  2846.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  2847.                  _("Width:"), 1.0, 0.5,
  2848.                  spinbutton, 1, FALSE);
  2849.   gtk_signal_connect (GTK_OBJECT (vals->adjustment[0]), "value_changed",
  2850.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  2851.               &psvals.width);
  2852.  
  2853.   spinbutton = gimp_spin_button_new (&vals->adjustment[1], psvals.height,
  2854.                      1e-5, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 2);
  2855.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  2856.                  _("Height:"), 1.0, 0.5,
  2857.                  spinbutton, 1, FALSE);
  2858.   gtk_signal_connect (GTK_OBJECT (vals->adjustment[1]), "value_changed",
  2859.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  2860.               &psvals.height);
  2861.  
  2862.   spinbutton = gimp_spin_button_new (&vals->adjustment[2], psvals.x_offset,
  2863.                      0.0, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 2);
  2864.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
  2865.                  _("X-Offset:"), 1.0, 0.5,
  2866.                  spinbutton, 1, FALSE);
  2867.   gtk_signal_connect (GTK_OBJECT (vals->adjustment[2]), "value_changed",
  2868.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  2869.               &psvals.x_offset);
  2870.  
  2871.   spinbutton = gimp_spin_button_new (&vals->adjustment[3], psvals.y_offset,
  2872.                      0.0, GIMP_MAX_IMAGE_SIZE, 1, 10, 0, 1, 2);
  2873.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  2874.                  _("Y-Offset:"), 1.0, 0.5,
  2875.                  spinbutton, 1, FALSE);
  2876.   gtk_signal_connect (GTK_OBJECT (vals->adjustment[3]), "value_changed",
  2877.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  2878.               &psvals.y_offset);
  2879.  
  2880.   toggle = gtk_check_button_new_with_label (_("Keep Aspect Ratio"));
  2881.   gimp_help_set_help_data (toggle, _("When toggled, the resulting image will be scaled to fit "
  2882.                      "into the given size without changing the aspect ratio."),
  2883.                "#keep_aspect_ratio"), 
  2884.   gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
  2885.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  2886.                       GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  2887.                       &psvals.keep_ratio);
  2888.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), psvals.keep_ratio);
  2889.   gtk_widget_show (toggle);
  2890.  
  2891.   /* Unit */
  2892.   uframe = gimp_radio_group_new2 (TRUE, _("Unit"),
  2893.                   save_unit_toggle_update,
  2894.                   vals, GINT_TO_POINTER (psvals.unit_mm),
  2895.  
  2896.                   _("Inch"),       GINT_TO_POINTER (FALSE), NULL,
  2897.                   _("Millimeter"), GINT_TO_POINTER (TRUE), NULL,
  2898.  
  2899.                   NULL);
  2900.   gtk_box_pack_start (GTK_BOX (vbox), uframe, FALSE, FALSE, 0);
  2901.   gtk_widget_show (uframe);
  2902.  
  2903.   gtk_widget_show (vbox);
  2904.   gtk_widget_show (frame);
  2905.  
  2906.   /* Rotation */
  2907.   frame = gimp_radio_group_new2 (TRUE, _("Rotation"),
  2908.                  gimp_radio_button_update,
  2909.                  &psvals.rotate, GINT_TO_POINTER (psvals.rotate),
  2910.  
  2911.                  "0",   GINT_TO_POINTER (0), NULL,
  2912.                  "90",  GINT_TO_POINTER (90), NULL,
  2913.                  "180", GINT_TO_POINTER (180), NULL,
  2914.                  "270", GINT_TO_POINTER (270), NULL,
  2915.  
  2916.                  NULL);
  2917.   gtk_box_pack_start (GTK_BOX (main_vbox[1]), frame, FALSE, FALSE, 0);
  2918.   gtk_widget_show (frame);
  2919.  
  2920.   /* Format */
  2921.   frame = gtk_frame_new (_("Output"));
  2922.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  2923.   gtk_box_pack_start (GTK_BOX (main_vbox[1]), frame, TRUE, TRUE, 0);
  2924.  
  2925.   vbox = gtk_vbox_new (FALSE, 2);
  2926.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  2927.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  2928.  
  2929.   toggle = gtk_check_button_new_with_label (_("PostScript Level 2"));
  2930.   gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
  2931.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  2932.                       GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  2933.                       &(vals->level));
  2934.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), vals->level);
  2935.   gtk_widget_show (toggle);
  2936.  
  2937.   toggle = gtk_check_button_new_with_label (_("Encapsulated PostScript"));
  2938.   gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
  2939.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  2940.                       GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  2941.                       &psvals.eps);
  2942.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), psvals.eps);
  2943.   gtk_widget_show (toggle);
  2944.  
  2945.   toggle = gtk_check_button_new_with_label (_("Preview"));
  2946.   gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
  2947.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  2948.                       GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  2949.                       &psvals.preview);
  2950.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), psvals.preview);
  2951.   gtk_widget_show (toggle);
  2952.  
  2953.   /* Preview size label/entry */
  2954.   table = gtk_table_new (1, 2, FALSE);
  2955.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  2956.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  2957.   gtk_widget_show (table);
  2958.  
  2959.   gtk_object_set_data (GTK_OBJECT (toggle), "set_sensitive", table);
  2960.   gtk_widget_set_sensitive (table, psvals.preview);
  2961.  
  2962.   spinbutton = gimp_spin_button_new (&adj, psvals.preview_size,
  2963.                      0, 1024, 1, 10, 0, 1, 0);
  2964.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  2965.                  _("Preview Size:"), 1.0, 0.5,
  2966.                  spinbutton, 1, FALSE);
  2967.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  2968.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  2969.               &psvals.preview_size);
  2970.   gtk_widget_show (spinbutton);
  2971.  
  2972.   gtk_widget_show (vbox);
  2973.   gtk_widget_show (frame);
  2974.  
  2975.   for (j = 0; j < sizeof (main_vbox) / sizeof (main_vbox[0]); j++)
  2976.     gtk_widget_show (main_vbox[j]);
  2977.  
  2978.   gtk_widget_show (hbox);
  2979.   gtk_widget_show (dialog);
  2980.  
  2981.   gtk_main ();
  2982.   gdk_flush ();
  2983.  
  2984.   psvals.level = (vals->level) ? 2 : 1;
  2985.  
  2986.   g_free (vals);
  2987.  
  2988.   return psint.run;
  2989. }
  2990.  
  2991. static void
  2992. save_ok_callback (GtkWidget *widget,
  2993.                   gpointer   data)
  2994. {
  2995.   psint.run = TRUE;
  2996.  
  2997.   gtk_widget_destroy (GTK_WIDGET (data));
  2998. }
  2999.  
  3000. static void
  3001. save_unit_toggle_update (GtkWidget *widget,
  3002.              gpointer   data)
  3003. {
  3004.   if (GTK_TOGGLE_BUTTON (widget)->active)
  3005.     {
  3006.       SaveDialogVals *vals;
  3007.       gdouble factor;
  3008.       gdouble value;
  3009.       gint    unit_mm;
  3010.       gint    i;
  3011.  
  3012.       vals    = (SaveDialogVals *) data;
  3013.       unit_mm = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (widget)));
  3014.  
  3015.       psvals.unit_mm = unit_mm;
  3016.  
  3017.       if (unit_mm)
  3018.     factor = 25.4;
  3019.       else
  3020.     factor = 1.0 / 25.4;
  3021.  
  3022.       for (i = 0; i < 4; i++)
  3023.     {
  3024.       value = GTK_ADJUSTMENT (vals->adjustment[i])->value * factor;
  3025.  
  3026.       gtk_adjustment_set_value (GTK_ADJUSTMENT (vals->adjustment[i]), value);
  3027.     }
  3028.     }
  3029. }
  3030.  
  3031. /* Misc utility from glib2 */
  3032. static gchar *
  3033. g_shell_quote (const gchar *unquoted_string)
  3034. {
  3035.   /* We always use single quotes, because the algorithm is cheesier.
  3036.    * We could use double if we felt like it, that might be more
  3037.    * human-readable.
  3038.    */
  3039.  
  3040.   const gchar *p;
  3041.   GString *dest;
  3042.   gchar *ret;
  3043.  
  3044.   g_return_val_if_fail (unquoted_string != NULL, NULL);
  3045.  
  3046.   dest = g_string_new ("'");
  3047.  
  3048.   p = unquoted_string;
  3049.  
  3050.   /* could speed this up a lot by appending chunks of text at a
  3051.    * time.
  3052.    */
  3053.   while (*p)
  3054.     {
  3055.       /* Replace literal ' with a close ', a \', and a open ' */
  3056.       if (*p == '\'')
  3057.         g_string_append (dest, "'\\''");
  3058.       else
  3059.         g_string_append_c (dest, *p);
  3060.  
  3061.       ++p;
  3062.     }
  3063.  
  3064.   /* close the quote */
  3065.   g_string_append_c (dest, '\'');
  3066.  
  3067.   ret = dest->str;
  3068.   g_string_free (dest, FALSE);
  3069.   return ret;
  3070. }
  3071.